جدول المحتويات
بدهيات الأنماط القياسية REGEX
الأنماط القياسية Regular Expression أو REGEX اختصارا هي وسيلة شائعة جدا في معالجة النصوص string manipulation في
- عمليات المطابقة Matching (مثلا فحص هل أدخل المستخدم بريد إلكتروني صحيح)
- والبحث (مثلا استخراج كل الروابط من ملف HTML)
- الاستبدال (وضع كل الروابط بين وسم <a>)
إن أكثر تطبيقاتها هي عمل parsers لكنها لا تقف عند هذا الحد. عمليات البحث والمطابقة للأنماط القياسية سريعة نسبيا حيث أنه أولا يتم تصنيف النمط compile وهي عملية تحوله من NFA أي nondeterministic finite automaton إلى DFA أي deterministic finite automaton في عملية تسمى Powerset construction ثم يتم تمرير حروف النص فيها.
أنواع الأنماط
- أنماط مستهلكة consuming وهي التي تطابق حرف أو أكثر وتستهلكها
- الأنماط الحرفية وهي التي نقصدها كما هي دون معنى خاص
- الانتماء لمجموعة set أو عدم الانتماء لها
- التجميع grouping وهو وضع عدة أنماط بين قوسين لبيان الأولية وهي نوعان capturing و non-capturing الأول يتم حفظه ويمكن الرجوع له back reference أما الثاني فلا.
- المحددات العددية للنمط السابق Quantification (مثل عدد مرات التكرار)
- أنماط جشعة greedy patterns وهي التي تبحث عن أطول تطابق وهذا هو السلوك التلقائي
- أنماط غير جشعة non-greedy patterns وهي التي تبحث عن أقصر تطابق
- أنماط غير مستهلكة non-consuming (وكأنها تطابق المؤشر الموجود بين الحروف وليس عدد من الحروف) مثل
- الموضعية (كبادية السطر أو نهايته أو بداية الكلمة)
- الشروط على ما سبق أو ما سيأتي دون استهلاكها
المطابقة الحرفية
الأنماط الحرفية هي التي نقصد المعنى الحرفي لها مثلا عندما نقول car فإننا نعني حرف c يتبعه حرف a يتبعه حرف r. علامة النقطة “.” تطابق أي حرف واحد مثلا p.t تطابق حرف p يليه أي حرف (بما في ذلك الرموز والمسافات) يليه t مثل pot و pet.
ويمكننا التخيير باستعمال علامة | مثلا apple|banana تطابق كلمة apple أو كلمة banana. ويجوز وضع علامة | أكثر من مرة
إن كان هناك معنى خاص لأي حرف وكنا نريده بشكل حرفي يمكنني تخطي المعنى الخاص بعلامة الشرطة المائلة العكسية \
الانتماء لمجموعة set
يتم اشتراط الحرف لمجموعة من الحروف عبر وضع كل الحروف الممكنة بين أقواس مربعة [ ] مثلا p[aei]n تطابق p يتبعه حرف من بين الحروف a أو e أو i ثم حرف n أي pan أو pen أو pin.
إن كانت الحروف متتابعة يمكن استخدام علامة - مثلا [a-z] تعني كل الحروف من a-z ومثلا [a-zA-Z] تعني كل الحروف a-z كبيرة وصغيرة.
لنفي الانتماء لمجموعة يمكن وضع علامة ^ بعد فتح القوس المربع مثلا a[^ ]b والتي تعني حرف a يتبعه أي شيء عدا المسافة ثم حرف b
التجميع grouping
يكون التجميع بوضع الأقواس حول النمط مثلا (apple|banana)
echo "banana eating monkey" | grep '\(apple\|banana\)' && echo matches echo "banana eating monkey" | egrep '(apple|banana)' && echo matches
يقوم البرنامج بحفظ كل قوس ويمكنك من العودة إليه لاحظة عبر back reference كما سنوضح ذلك لاحقا.
المحددات العددية
- علامة النجمة * تكرار النمط صفر أو أكثر من المرات
- علامة الزائد + تكرار النمط واحد أو أكثر من المرات (اشتراط وجوده مرة على الأقل)
- علامة السؤال ? تكرار النمط مرة على الأكثر (أي أن النمط اختياري)
- تحديد التكرار بين رقمين {n,m} أي على الأقل n مرة ولا يزيد عن m مرة
إذا كان هناك أكثر من خيار فإن المطابقة ستكون لأطول خيار وهذا ما يعرف بالنمط الجشع greedy. وضع علامة السؤال بعد النجمة يعني يعني تحويلها إلى نمط غير جشع مثلا a[a-z]*?b تعني أقصر تطابق لكلمة تبدأ ب a وتنتهي ب b مثلا الجزء المطابق في abbbbbbbb هو أول حرفين فقط. المطابقة غير الجشعة غير قياسية (غير موجود في grep) بل هي موجودة في مكتبة perl (وكل اللغات التي تستخدم مكتبتها) والتي تقلدها.
ومن أشهر الأمثلة التي نحتاج هذه الميزة فيها مطابقة النص داخل وسم <b></b> لاحظ المشكلة (وهي أن is a مظللة بالأحمر) ولاحظ الحل القياسي لها.
المحددات الموضعية
المحددات الموضعية كما ذكرنا سابقا لا تستهلك من المدخلات شيئا بل فقط تحدد المكان.
- علامة ^ وتعني بداية النص أو السطر (إن كانت المطابقة متعددة الأسطر)
- علامة $ وتعني نهاية النص أو السطر
- حدود الكلمة \b وتعني على الحد الفاصل بين الكلمات (يعني إن كان قبلها محرف يجب أن لا يكون حرفا ولا رقما ولا _)
مثلا لعرض كل الأسطر التي تبدأ بكلمة Error اكتب
grep '^Error' /path/to/file
مثلا للبحث عن كلمة test كاملة وليس testing علينا اشتراط أن تقع على حد الكلمة من الطرفين كما في آخر مثال في الصورة