تُستخدم التعبيرات العادية بشكل أساسي لمعالجة السلاسل، ومن الملائم جدًا استخدامها لمطابقة السلاسل واستخراجها واستبدالها.
ومع ذلك، فإن تعلم التعبيرات النمطية لا يزال صعبًا إلى حد ما، حيث أن المفاهيم مثل المطابقة الجشعة، والمطابقة غير الجشعة، والمجموعات الفرعية الملتقطة، والمجموعات الفرعية غير الملتقطة ليست صعبة الفهم للمبتدئين فحسب، بل أيضًا للعديد من الأشخاص الذين عملوا لعدة سنوات.
إذن ما هي أفضل طريقة لتعلم التعبيرات العادية؟ كيف تتقن التعبيرات العادية بسرعة؟
أوصي بطريقة لتعلم القواعد العادية التي أعتقد أنها جيدة جدًا: التعلم من خلال AST .
مبدأ مطابقة التعبيرات العادية هو تحليل سلسلة النمط إلى AST، ثم استخدام AST هذا لمطابقة السلسلة المستهدفة.
سيتم تخزين المعلومات المختلفة في سلسلة النمط في AST بعد التحليل. AST عبارة عن شجرة بناء جملة مجردة، كما يوحي الاسم، فهي شجرة منظمة وفقًا للبنية النحوية. من خلال بنية AST، يمكنك بسهولة معرفة بناء الجملة الذي تدعمه التعبيرات العادية.
كيفية عرض AST للتعبير العادي؟
يمكنك مشاهدته بصريا من خلال الموقع asexplorer.net:
من خلال تحويل لغة التحليل إلى RegExp، يمكنك تصور AST للتعبيرات العادية.
كما ذكرنا من قبل، AST عبارة عن شجرة منظمة وفقًا لقواعد اللغة، لذلك يمكن فرز القواعد النحوية المختلفة بسهولة من بنيتها.
ثم دعونا نتعلم بناء الجملة المختلفة من منظور AST:
لنبدأ بالصيغة البسيطة /abc/ يمكن أن يتطابق مثل هذا النظام مع سلسلة 'abc'، ويكون AST الخاص به على النحو التالي:
3 Char، القيم هي a، b، c على التوالي، النوع بسيط. المطابقة اللاحقة هي اجتياز AST ومطابقة هذه الأحرف الثلاثة على التوالي.
لقد اختبرناه باستخدام exec API:
العنصر 0 هو السلسلة المطابقة، والفهرس هو فهرس البداية للسلسلة المطابقة. الإدخال هو سلسلة الإدخال.
لنحاول استخدام الأحرف الخاصة مرة أخرى:
/ddd/ يعني مطابقة ثلاثة أرقام.d هو حرف أولي (حرف تعريفي) له معنى خاص تدعمه التعبيرات العادية.
يمكننا أيضًا أن نرى من خلال AST أنه على الرغم من أنها أيضًا Char، إلا أن نوعها في الواقع هو meta:
يمكن مطابقة أي رقم باستخدام الحرف d الأولي:
يمكن رؤية أي منها عبارة عن أحرف وصفية وأيها عبارة عن أحرف بسيطة بنظرة سريعة من خلال AST.
يدعم العادي تحديد مجموعة من الأحرف من خلال []، مما يعني أنه يمكن مطابقة أي من الأحرف.
يمكننا أيضًا أن نرى من AST أنه مغلف بطبقة من CharacterClass، مما يعني فئة الحرف، أي أنه يمكن أن يتطابق مع أي حرف يحتوي عليه.
وهذا بالفعل هو الحال قيد الاختبار:
تدعم التعبيرات العادية تحديد عدد مرات تكرار حرف معين، باستخدام النموذج {from,to}،
على سبيل المثال، /b{1,3}/ يعني تكرار الحرف b من 1 إلى 3 مرات ، /[abc ]{1,3}/ يعني أن فئة الأحرف a/b/c تتكرر من 1 إلى 3 مرات.
كما يتبين من AST، فإن بناء الجملة هذا يسمى التكرار:
يحتوي على سمة مُحدِّد الكمية، والنوع هنا هو النطاق من 1 إلى 3.
تدعم التعبيرات العادية أيضًا اختصارات بعض محددات الكمية، مثل + تشير إلى 1 إلى مرات لا حصر لها، * تشير إلى 0 إلى مرات لا حصر لها، و ? تشير إلى 0 أو 1 مرة.
وهي أنواع مختلفة من محددات الكمية:
وقد يتساءل بعض الطلاب ما معنى صفة الجشع هنا؟
الجشع يعني الجشع تشير هذه السمة إلى ما إذا كان هذا التكرار عبارة عن مباراة جشعة أم مباراة غير جشعة.
إذا قمت بإضافة ؟ بعد المحدد الكمي، فستجد أن الجشع يصبح خطأ، مما يعني التحول إلى المطابقة غير الجشعة:
فماذا يعني الجشع وغير الجشع؟
دعونا نرى مثالا.
مطابقة التكرار الافتراضية جشعة وستستمر في المطابقة طالما تم استيفاء الشروط، لذلك يمكن مطابقة acbac هنا.
إضافة ? بعد أن يتحول مُحدِّد الكمية إلى غير جشع، وسيتم مطابقة الأول فقط:
هذه هي المطابقة الجشعة والمطابقة غير الجشعة من خلال AST، يمكننا أن نعرف بوضوح أن الجشع وغير الجشع مخصصان للقواعد المتكررة.
يدعم التعبير العادي وضع جزء من السلسلة المطابقة في مجموعة فرعية وإعادتها من خلال ().
ألق نظرة على AST:
يسمى AST المقابل المجموعة.
وستجد أن لديه خاصية الالتقاط، والتي تكون قيمتها الافتراضية صحيحة:
ماذا يعني هذا؟
هذا هو بناء الجملة لالتقاط المجموعة الفرعية.
إذا كنت لا تريد التقاط مجموعات فرعية، يمكنك الكتابة بهذه الطريقة (؟:aaa)
انظروا، أصبح الالتقاط كاذبا.
ما الفرق بين الالتقاط وعدم الالتقاط؟
دعونا نحاول ذلك:
أوه، اتضح أن سمة الالتقاط للمجموعة تمثل ما إذا كان سيتم استخراجها أم لا.
يمكننا أن نرى من AST أن الالتقاط مخصص للمجموعات الفرعية، والإعداد الافتراضي هو الالتقاط، مما يعني أنه يمكنك التبديل إلى عدم الالتقاط من خلال ?: ولن يتم استخراج محتوى المجموعة الفرعية.
نحن بالفعل على دراية باستخدام AST لفهم بناء الجملة العادي، ولكن دعونا نلقي نظرة على شيء أكثر صعوبة قليلاً:
تدعم التعبيرات العادية التعبير عن تأكيدات النظرة المستقبلية من خلال بناء جملة (?=xxx)، والذي يستخدم للحكم على ما إذا كانت السلسلة مسبوقة بسلسلة معينة.
من خلال AST، يمكنك أن ترى أن بناء الجملة هذا يسمى تأكيد، والنوع هو lookahead، وهو ما يعني التطلع، فقط مطابقة للمعنى السابق:
ماذا يعني هذا؟ لماذا تكتب هذا؟ ما الفرق بين /bbb(ccc)/ و/bbb(?:ccc)/؟
دعونا نحاول ذلك:
يمكن رؤيته من النتائج:
/bbb(ccc)/ يطابق المجموعة الفرعية لـ ccc ويستخرج هذه المجموعة الفرعية لأنه تم التقاط المجموعة الفرعية الافتراضية.
/bbb(?:ccc)/ يطابق المجموعة الفرعية لـ ccc ولكن لم يتم استخراجه لأننا قمنا بتعيين المجموعة الفرعية بحيث لا يتم التقاطها من خلال ?:.
/bbb(?=ccc)/ لم يتم استخراج المجموعة الفرعية المطابقة لـ ccc، مما يشير إلى أنها غير قابلة للالتقاط أيضًا. الفرق بينه وبين ؟: هو أن ccc لا يظهر في نتيجة المطابقة.
هذه هي طبيعة تأكيد البحث الأمامي: يعني تأكيد البحث الأمامي أن سلسلة معينة مسبوقة بسلسلة معينة، والمجموعة الفرعية المقابلة غير ملتقطة، ولن تظهر السلسلة المؤكدة في النتيجة المطابقة.
إذا لم تكن متبوعة بهذه السلسلة، فلن تتطابق:
قم بتغيير ?= إلى ؟! ثم يتغير المعنى عبر AST:
على الرغم من أنه لا يزال يتم التأكيد على تأكيد النظرة الأمامية أولاً، إلا أن هناك سمة سلبية إضافية وهي true.
والمعنى واضح في الأصل أن الإمام وتر معين، وبعد النفي يعني أن الإمام ليس وتراً معيناً.
ثم تكون نتيجة المطابقة عكس ذلك تمامًا:
الآن يتطابق فقط إذا لم تكن هناك سلسلة معينة أمامه، وهذا تأكيد سلبي.
إذا كان هناك تأكيد سابق، فمن الطبيعي أن يكون هناك تأكيد لاحق، أي أنه لن يتطابق إلا إذا كانت متبوعة بسلسلة معينة.
وبنفس الطريقة يمكن أيضًا إنكار:
من السهل التفكير في AST المطابق لـ (?<=aaa)، وهو تأكيد النظر إلى الخلف:
AST المطابق لـ (?<!aaa) هو إضافة سمة سلبية:
يعد تأكيد النظرة المستقبلية والتأكيد النظري من أصعب صيغ التعبير العادي التي يمكن فهمها، فهل من الأسهل فهمها إذا تعلمتها من خلال AST ~
التعبيرات العادية هي أداة مريحة للغاية لمعالجة السلاسل، ولكنها لا تزال إلى حد ما. يصعب تعلم العديد من الأشخاص بشأن بناء الجملة مثل المطابقة الجشعة، والمطابقة غير الجشعة، والتقاط المجموعات الفرعية، والمجموعات الفرعية غير الجذابة، والتأكيدات الأمامية، والتأكيدات الخلفية، وما إلى ذلك.
أوصي بتعلم القواعد العادية من خلال AST، وهي شجرة كائنات منظمة وفقًا للبنية النحوية، ويمكن توضيح تركيب الجمل المختلفة بسهولة من خلال أسماء وسمات عقد AST.
على سبيل المثال، أوضحنا من خلال AST:
بناء جملة التكرار (التكرار) يكون على شكل حرف + محدد كمي. الإعداد الافتراضي هو المطابقة الجشعة (الجشع صحيح)، وهو ما يعني المطابقة حتى لا تتم إضافة ? بعد أن يتحول المحدد الكمي إلى غير -المطابقة الجشعة، تتوقف عند مطابقة حرف واحد.
يُستخدم بناء جملة المجموعة الفرعية (المجموعة) لاستخراج سلسلة معينة. الإعداد الافتراضي هو الالتقاط (الالتقاط صحيح)، مما يعني أن الاستخراج مطلوب. يمكنك التبديل إلى عدم الالتقاط من خلال (?:xxx)، الذي يطابق فقط ولكن لا يستخرج .
يمثل بناء جملة التأكيد (Assertion) سلسلة معينة قبله أو بعده، وهو مقسم إلى تأكيد lookahead وتوكيد lookbehind. والصيغة هي (?=xxx) و(?<=xxx) على التوالي النفي (السلبي صحيح)، وهو ما يعني العكس تماما.
هل هو الفهم العميق لبناء الجملة في المستندات المختلفة أم الفهم العميق لبناء الجملة في المترجم؟
لا حاجة للسؤال، يجب أن يكون المترجم!
إذن فمن الأفضل بطبيعة الحال تعلم القواعد من خلال شجرة بناء الجملة التي يتم تحليلها وفقًا للقواعد بدلاً من تعلم المستند.
ينطبق هذا على التعبيرات العادية، كما ينطبق أيضًا على تعلم القواعد النحوية الأخرى. إذا كان بإمكانك تعلم القواعد باستخدام AST، فلن تحتاج إلى قراءة الوثائق.