صياغة التعبيرات النمطية في PHP

من موسوعة حسوب
< PHP
مراجعة 15:09، 22 أبريل 2018 بواسطة عبد اللطيف ايمش (نقاش | مساهمات)
(فرق) → مراجعة أقدم | المراجعة الحالية (فرق) | مراجعة أحدث ← (فرق)
اذهب إلى التنقل اذهب إلى البحث

فيما يلي وصف لصياغة ودلالات التعبيرات النمطية التي يدعمها PCRE. وتوصف أيضًا التعبيرات النمطية في توثيق Perl وفي عدد من الكتب الأخرى، وبعضها يحتوي على أمثلة كثيرة. ويغطيها كتاب "Mastering Regular Expressions"، لجيفري فريدل Jeffrey Friedl الذي نشرته دار نشر O'Reilly ‏(ISBN 1-56592-257-3)، بتفصيل كبير. الوصف هنا غرضه التوثيق المرجعي.

التعبير النمطي هو نمط يطابق سلسلة موضوع البحث من اليسار إلى اليمين. وتصطف معظم الأحرف لأنفسها بنمطٍ ما، وتطابق الأحرف المقابلة في موضوع البحث. كمثال صغير، يتطابق النمط The quick brown fox مع جزء من سلسلةٍ هدف تحتوي العبارة السابقة نفسها.

الفواصل (Delimiters)

عند استخدام دوال PCRE، يجب أن يكون النمط محاطًا بفواصل. يمكن أن يكون الفاصل أي حرف غير هجائي رقمي وليس الشَرطة المائلة العكسية أو المسافة.

وتستخدم في كثير من الأحيان الشرطة المائلة للأمام / وعلامة # أ و ~ كفواصل. فيما يلي كافة أمثلة أشكال الفواصل الصالحة.

/foo bar/
#^[^0-9]$#
+php+
%[a-zA-Z0-9_-]%

من الممكن أيضًا استخدام الأقواس كفواصل نمط حيث يكون قوسي الفتح والإغلاق هما فاصلا البداية والنهاية على التوالي. وتُعد () ، و {} ، و [] و <> جميعها أزواج فواصل أنماط على شكل أقواس.

(this [is] a (pattern))
{this [is] a (pattern)}
[this [is] a (pattern)]
<this [is] a (pattern)>

لا يلزم تهريب فواصل الأنماط من أقواس عندما تُستخدم كأحرف خاصة لها دلالة (meta characters) داخل النمط، ولكن كما هو الحال مع الفواصل الأخرى، يجب أن تُهرَّب عند استخدامها بذاتها كأحرف (أي القيمة الحرفية لها، literal value). إذا كان من الضروري مطابقة الفاصل داخل النمط، يجب أن يُهرَّب باستخدام شرطة مائلة عكسية (backslash). وإذا ظهر الفاصل بشكل متكرر داخل النمط، فمن المستحسن اختيار فاصل آخر لتسهيل القراءة.

/http:\/\//
#http://#

يمكن استخدام الدالة preg_quote()‎ لتهريب سلسلة نصية لإضافتها في نمطِ ما، ويمكن استخدام المعامل الثاني الاختياري لها لتحديد الفاصل المراد تهريبه. يمكنك إضافة معدِّلات الأنماط (pattern modifiers) بعد فاصل النهاية. فيما يلي مثال على المطابقة غير الحساسة لحالة الأحرف:

#[a-z]#i

الأحرف الخاصة (Meta-characters)

تأتي قوة التعبيرات النمطية من القدرة على تضمين بدائل وتكرارات في النمط، وذلك عن طريق ترميزها داخله باستخدام الأحرف الخاصة، والتي تُفسَّر بطريقة خاصة ولا تمثل نفسها كأحرف.

هناك مجموعتان مختلفتان من الأحرف الخاصة: تلك التي يُتعرَّف عليها في أي مكان في النمط فيما عدا الأقواس المربعة []، وتلك التي يُتعرَّف عليها بين الأقواس المربعة. في حالة الأقواس المربعة الخارجية، تستخدم الأحرف الخاصة التالية:

الأحرف الخاصة خارج الأقواس المربعة

الحرف الخاص الوصف
\ حرف التهريب العام وله عدة استخدامات.
^ مطابقة بداية الموضوع (أو السطر، في وضع متعدد الأسطر).
$ مطابقة نهاية الموضوع أو قبل إنهاء سطر جديد (أو نهاية السطر، في وضع متعدد الأسطر).
. تطابق أي حرف باستثناء محرف السطر الجديد (افتراضيًا).
[ بداية تعريف فئة الحرف.
] نهاية تعريف فئة الحرف.
| بداية فرع بديل.
) بداية نمط فرعي.
( نهاية نمط فرعي.
? توسيع معنى )، ومحدد الكمية 0 أو 1 أيضًا، ويُبطئ أيضا من محددات الكمية الجشعة (انظر [expressions&veaction=edit#.D8.A7.D9.84.D8.AA.D9.83.D8.B1.D8.A7.D8.B1|التكرار])
* محدد الكمية 0 أو أكثر.
+ محدد الكمية 1 أو أكثر.
} بداية محدد الكمية.
{ نهاية محدد الكمية.

يسمى جزء النمط الموجود بين أقواس مربعة فئة الأحرف. في فئة الأحرف تكون الأحرف الخاصة الوحيدة المستخدمة هي:

الأحرف الخاصة داخل الأقواس المربعة (فئات الأحرف)

الحرف الخاص الوصف
\ حرف التهريب العام.
^ نفي الفئة، ولكن فقط إذا كان الحرف الأول.
- تشير إلى مجال من الأحرف.

تصف الأقسام التالية استخدام كل من الأحرف الخاصة.

تسلسلات التهريب (Escape Sequences)

لحرف الشرطة المائلة العكسية (Backslash) عدة استخدامات. أولاً، إذا تبعها حرف غير هجائي رقمي، فإنه يُزيل أي معنىً خاص قد يكون لهذا الحرف. وينطبق استخدام الشرطة المائلة العكسية كحرف تهريب في كلٍ من داخل وخارج فئات الأحرف.

على سبيل المثال، إذا كنت تريد مطابقة الحرف "*"، فستكتب "‎\*‎" في النمط. وينطبق هذا على ما إذا كان سيُفسّر الحرف التالي على أنه حرف خاص أم لا، لذلك فمن الأكثر أمانًا دائمًا أن تسبق الأحرف غير الهجائية الرقمية بالشرطة المائلة العكسية "\" لتحديد أنها تعني نفسها حرفيًا. وعلى وجه الخصوص، إذا كنت تريد مطابقة الشرطة المائلة العكسية، فستكتب "\\".

ملاحظة: السلاسل النصية في PHP والمُحاطة بعلامات اقتباس أحادية أو ثنائية تعطي معنىً خاص للشَرطة المائلة للخلف. وبالتالي، إذا كانت \ يجب أن تتطابق مع تعبير نمطي \\، فيجب عندئذٍ استخدام "\\\\" أو '\\\\' في شيفرة PHP.

إذا تُرجِم نمط باستخدام خيار PCRE_EXTENDED، فستُتجاهل المسافات في النمط (بخلاف فئة الحرف) والأحرف بين "#" خارج فئة الحرف وحرف السطر الجديد التالي. ويمكن استخدام الشرطة المائلة العكسية لتضمين مسافة أو "#" كجزء من النمط.

يوفر الاستخدام الثاني للشَرطة المائلة العكسية طريقة لترميز الأحرف غير المطبوعة في الأنماط بطريقة مرئية. لا توجد قيود على مظهر الأحرف غير المطبوعة، بصرف النظر عن الصفر الثنائي (binary zero) الذي ينهي نمطًا، ولكن عند إعداد نمط ما بواسطة تحرير النص، يكون من الأسهل استخدام أحد تسلسلات التهريب التالية عن استخدام الحرف الثنائي الذي يمثلها:

  • ‎\a‏: التنبيه، وهو محرف BEL‏ ‎(hex 07‎‎)‎.
  • ‎\cx: أي "control-x"، إذ تمثل x أي حرف.
  • ‎\e: الهروب (escape) ‏(hex 1B).
  • ‎\f: محرف الانتقال إلى صفحة جديدة (hex 0C‎).
  • ‎\n: محرف السطر الجديد (new line) أو (hex 0A).
  • ‎\p{xx}‎: حرف مع خاصية xx، راجع خصائص unicode لمزيد من المعلومات.
  • ‎\P{xx}‎: حرف بدون خاصية xx، راجع خصائص unicode لمزيد من المعلومات.
  • ‎\r: محرف العودة إلى بداية السطر (carriage return) أو (hex 0D).
  • ‎\R: محرف فاصل السطر (line break): تطابق ‎\r و ‎\n و ‎\r‎\n.
  • ‎\t: محرف مسافة الجدولة (tab) أو (hex 09).
  • ‎\xhh: حرف مع رمز ست عشري hh.
  • ‎\ddd: حرف مع رمز ثماني octal ddd، أو مرجع خلفي (backreference).

يكون التأثير الدقيق للسلسلة "‎\‎‎cx" كما يلي: إذا كان "x" هو حرف صغير، فسيُحوّل إلى حرف كبير. ثم يُعكس البت رقم 6 من الحرف (hex 40). وهكذا يصبح "cz" هو hex 1A، لكن "‎\c{‎" يصبح hex 3B، بينما "‎\c;‎" يصبح hex 7B.

بعد "‎\x"، يُقرأ ما يصل إلى رقمين ست عشريين (يمكن أن تكون الأحرف كبيرة أو صغيرة). ويُسمح في وضع UTF-8 باستخدام الصيغة "‎\x{...}‎"، إذ تكون محتويات الأقواس عبارة عن سلسلة من الأرقام الست عشرية. ويفسّر على أنه حرف UTF-8 ورقم الرمز الخاص به هو الرقم الست عشري المُعطى. يتطابق تسلسل التهريب الست عشري الأصلي، ‎\xhh، مع حرف UTF-8 ثنائي البايت إذا كانت القيمة أكبر من 127.

يُقرأ بعد "‎\0" ما يصل إلى رقمين ثُمانييّن إضافيين. في كلتا الحالتين، إذا كان هناك أقل من عددين، فستُستخدم تلك الموجودة فقط. وبالتالي يحدد التسلسل "‎\0 \x \07" اثنين من الأصفار الثنائية متبوعة بحرف BEL. تأكد من توفير رقمين بعد الصفر الأول إذا كان الحرف التالي هو نفسه عدد ثماني.

يُعد تعامل مع الشرطة المائلة العكسية متبوعةً برقم غير 0 أمرًا معقدًا. خارج فئة الحرف، يقرأ PCRE ذلك وأية أعداد تالية كرقم عشري. إذا كان الرقم أقل من 10، أو إذا كان هناك على الأقل العديد من أقواس الإلتقاط اليسرى السابقة في التعبير، فسيُؤخذ التسلسل بأكمله كمرجع خلفي (back reference). وسوف يرد وصف لكيفية عمل هذا في وقت لاحق، بعد مناقشة الأنماط الفرعية المُحاطة بالأقواس.

داخل فئة الحرف، أو إذا كان الرقم العشري أكبر من 9 ولم يكن هناك العديد من الأنماط الفرعية اللاقِطة، فسيُعيد PCRE قراءة ما يصل إلى ثلاثة أرقام ثُمانية بعد الشرطة المائلة العكسية، ويولّد بايتًا واحدًا من 8 بتات أقصى اليمين من القيمة. وتعنى أي أرقام لاحقة نفسها بالمعنى الحرفي. ومثال على ذلك:

  • ‎\040: هي طريقة أخرى لكتابة المسافة (space).
  • ‎\40: هي نفسها، شريطة أن يكون هناك أقل من 40 نمط فرعي مُلتقِط سابقًا.
  • ‎\7: تمثِّل دائمًا المرجع الخلفي.
  • ‎\11: قد يكون مرجعًا خلفيًا، أو طريقة أخرى لكتابة مسافة الجدولة (tab).
  • ‎\011: هي دائمًا مسافة الجدولة.
  • ‎\0113: هي مسافة الجدولة متبوعة بالحرف "3".
  • ‎\113: هي الحرف ذو الرمز الثماني 113 (إذ لا يمكن أن يكون هناك أكثر من 99 مرجعًا خلفيًا).
  • ‎\377: هي بايت يتكون بالكامل من 1 بت.
  • ‎\81: هي إما مرجع خلفي، أو صفر ثنائي يتبعه الحرفان "8" و "1".

لاحظ أن القيم الثُمانية 100 أو أكبر يجب ألا تُقدم بصفرٍ سابق، لأنه لا يُقرأ أكثر من ثلاثة أرقام ثمانية.

يمكن استخدام كل التسلسلات التي تُعرِّف قيمة بايت واحد داخل وخارج فئات الأحرف. بالإضافة إلى ذلك، داخل فئة الحرف، يُفسّر التسلسل "‎\b" كمحرف الفراغ الخلفي (backspace) (ست عشري 08). ولها معنى مختلف خارج فئة الحرف (انظر أدناه).

الاستخدام الثالث للشرطة المائلة العكسية (Backslash) هو تحديد أنواع الأحرف العامة:

  • ‎\d: أي رقم عشري.
  • ‎\D‎: أي حرف ليس رقمًا عشريًا.
  • ‎\h: أي حرف مسافة (whitespace) أفقي.
  • ‎\H: أي حرف غير أحرف المسافة الأفقي.
  • ‎\s: أي حرف مسافة.
  • ‎\S: أي حرف غير أحرف المسافة.
  • ‎\v: أي حرف مسافة رأسية.
  • ‎\V: أي حرف غير أحرف المسافة الرأسية.
  • ‎\w: أي حرف يمكن أن يكون موجودًا في كلمة (word).
  • ‎\W: أي حرف لا يمكن أن يكون موجودًا في كلمة.

كل زوج من تسلسلات التهريب يُقسِّم المجموعة الكاملة من الأحرف إلى مجموعتين منفصلتين. يتطابق أي حرف عادي مُعطى مع تسلسل وحيد فقط من كل زوج.

أحرف المسافة "whitespace" هي HT ‏(horizontal tab، رمزه 9، وهو مسافة الجدول الأفقية)‎ و LF ‏(line feed، رمزه 10، وهو محرف الانتقال إلى سطرٍ جديد)‎ و FF‏ (form feed، رمزه 12، وهو محرف الانتقال إلى صفحة جديدة)‎ و CR ‏(carriage return، رمزه 13، وهو محرف العودة إلى بداية السطر)‎ والمسافة العادية (32). ومع ذلك، في حالة حدوث مطابقة خاصة بالمحليّة (locale) المستخدمة، يمكن أيضًا اعتبار الأحرف التي تكون رموزها ضمن النطاق 128-255 كأحرف مسافة، على سبيل المثال، المحرف NBSP‏ (non-breaking space، رمزه A0).

الحرف من أحرف الكلمة (word) هو أي حرف أو رقم أو حرف شرطة سفلية. يمكن التحكم في تعريف الحروف والأعداد من خلال جداول الأحرف الخاصة بوحدة PCRE، وقد يختلف ذلك في حالة حدوث مطابقة خاصة باللغة المحلية. على سبيل المثال، في اللغة "fr" (الفرنسية) المحلية، تُستخدم بعض رموز الأحرف أكبر من 128 للحروف ذات الحركات (accented)، وتُطابق هذه الأحرف بواسطة ‎\w.

يمكن أن تظهر تسلسلات نوع الحرف هذه داخل وخارج فئات الأحرف. ويتطابق كل منها مع حرف واحد من النوع المناسب. إذا كانت نقطة المطابقة الحالية في نهاية السلسلة النصية للهدف، فستفشل جميعها نظرًا لعدم وجود حرف مطابق.

الاستخدام الرابع للشرطة المائلة العكسية هو لبعض التأكيدات البسيطة. إذ يحدد التوكيد شرطًا يجب الوفاء به عند نقطة معينة في المطابقة، دون «استهلاك» (أو مطابقة) أي أحرف من السلسلة النصية للهدف. فيما يلي وصف استخدام الأنماط الفرعية لتأكيدات أكثر تعقيدًا. تأكيدات الشرطة المائلة العكسية هي:

  • ‎\b: حدود الكلمة.
  • ‎\B: ليست حدود الكلمة.
  • ‎\A: بداية السلسلة النصية الهدف (مستقل عن وضع متعدد الأسطر).
  • ‎\Z: نهاية السلسلة النصية الهدف أو السطر الجديد في النهاية (مستقل عن الوضع متعدد الأسطر).
  • ‎\z: نهاية السلسلة النصية الهدف (مستقل عن وضع متعدد الأسطر).
  • ‎\G: أول موقع مطابقة في السلسلة النصية الهدف.

قد لا تظهر هذه التأكيدات في فئات الأحرف (لكن لاحظ أن "‎\b" لها معنى مختلف، ألا وهو محرف المسافة الخلفية، وذلك داخل فئة الحرف).

حدود الكلمات هو موضع في السلسلة النصية الهدف حيث لا يتطابق الحرف الحالي والحرف السابق مع ‎\w أو ‎\W (أي تطابق أحدهما ‎\w وتطابق الأخرى ‎\W)، أو بداية السلسلة النصية أو نهايتها إذا تطابق الحرف الأول أو الأخير مع ‎\w على التوالي.

تختلف التأكيدات ‎\A و ‎\Z و ‎\z عن التأكيدات التقليدية $ و ^ (الموصوفة في المرتكزات) في أنها تتطابق فقط في بداية ونهاية السلسلة النصية الهدف، أيًا كانت الخيارات التي تُعيّن. ولا تتأثر بالخيارات PCRE_MULTILINE أو PCRE_DOLLAR_ENDONLY. الفرق بين ‎\Z و ‎\z هو أن ‎\Z تُطابق قبل سطر جديد الذي يكون الحرف الأخير من السلسلة النصية وكذلك في نهايتها، بينما ‎\z تُطابق فقط في النهاية.

يكون التوكيد ‎\G صحيحًا فقط عندما يكون موضع المطابقة الحالي في نقطة بداية المطابقة، كما هو محدد بواسطة الوسيط offset في الدالة preg_match()‎‎. وهو يختلف عن ‎\A عندما تكون قيمة offset غير صفرية.

يمكن استخدام ‎\Q و ‎\E لتجاهل حروف التعبيرات النمطية الخاصة في النمط. على سبيل المثال: ‎\w+\Q.$.\E$‎ ستطابق واحدًا أو أكثر من أحرف الكلمة، متبوعًا بـ .$. حرفيًا وترتكز في نهاية السلسلة النصية.

يمكن استخدام ‎\K لإعادة تعيين بدء المطابقة. على سبيل المثال، يتطابق النمط foo\Kbar مع "foobar"، لكنه يفيد بأنه يطابق "bar". ولا يتداخل استخدام ‎\K مع إعداد سلاسل نصية فرعية مُلتقَطة. على سبيل المثال، عندما يتطابق النمط ‎(foo)\Kbar مع "foobar"، فإن السلسلة النصية الفرعية الأولى لا تزال مضبوطة على "foo".

خصائص أحرف Unicode

منذ الإصدار 5.1.0، تتوافر ثلاثة تسلسلات تهريب إضافية لتتناسب مع أنواع الحروف العامة عند تحديد وضع UTF-8، وهي:

  • ‎‎\p{xx}‎: حرف مع خاصية xx.
  • ‎‎\P{xx}‎: حرف بدون خاصية xx.
  • ‎‎\X: تسلسل Unicode مُوسَّع.

تقتصر أسماء الخصائص التي يمثلها xx أعلاه على خصائص فئة Unicode العامة. يحتوي كل حرف على خاصية واحدة بالضبط، تُحدد باختصار من حرفين. للتوافق مع لغة Perl، يمكن تحديد النفي بتضمين علامة ^ بين قوس الفتح واسم الخاصية. على سبيل المثال، ‎‎‎\p{^ Lu}‎ هو نفسه ‎‎‎\P{Lu}‎،

إذا حُدِد حرف واحد فقط مع ‎‎‎\p أو ‎‎‎\P، فإنه سيتضمن جميع الخصائص التي تبدأ بهذا الحرف. في هذه الحالة، وفي غياب النفي، تكون الأقواس المعقوفة في تسلسل التهريب اختيارية؛ المثالان التاليان لهما نفس التأثير:

  • ‎‎\p{L}‎
  • ‎‎\pL

رموز الخواص المدعومة

الخاصية المتطابقات ملاحظات
C أخرى.
Cc التحكم.
Cf التنسيق.
Cn غير المُعيَّنة.
Co استخدام خاص.
Cs البديل.
L الحرف. يتضمن الخصائص التالية: Ll و Lm و Lo و Lt و Lu.
Ll حرف صغير.
Lm حرف تعديل.
Lo حرف آخر.
Lt حرف في حالة العنوان.
Lu حرف كبير.
M علامة.
Mc علامة تباعُد.
Me علامة تضمين.
Mn علامة غير التباعُد.
N رقم.
Nd عدد عشري.
Nl رقم الحرف.
No رقم آخر.
P علامة الترقيم.
Pc علامة ترقيم رابطة.
Pd علامة ترقيم الشرطة.
Pe علامة ترقيم الإغلاق.
Pf علامة الترقيم النهائية.
Pi علامة الترقيم البادئة.
Po علامات ترقيم أخرى.
Ps علامة الترقيم الإفتتاحية.
S رمز.
Sc رمز العملة.
Sk رمز تعديل.
Sm رمز رياضي.
So رمز آخر.
Z فاصل.
Zl فاصل السطور.
ZP فاصل الفقرة.
Zs فاصل المسافة.

لا تدعم PCRE الخصائص الممتدة مثل InMusicalSymbols.

لا يؤثر تحديد مطابقة حالة حساسية الأحرف (بدون حساسية) على تسلسلات التهريب هذه. على سبيل المثال، يطابق ‎‎‎\p{Lu}‎ دائمًا الأحرف الكبيرة فقط.

تُعرَّف مجموعات أحرف Unicode على أنها تنتمي إلى كتابات معينة. يمكن مطابقة حرف من إحدى هذه المجموعات باستخدام اسم المخطوطة (script). ومثال على ذلك:

  • ‎‎\p{Greek}‎
  • ‎‎\P{Arabic}‎

المخطوطات التي ليست جزءًا من مخطوطة مُحددة قد جُمِعت معًا تحت الاسم Common. القائمة الحالية للكتابات هي:

Arabic Armenian Avestan Balinese Bamum
Batak Bengali Bopomofo Brahmi Braille
Buginese Buhid Canadian_Aboriginal Carian Chakma
Cham Cherokee Common Coptic Cuneiform
Cypriot Cyrillic Deseret Devanagari Egyptian_Hieroglyphs
Ethiopic Georgian Glagolitic Gothic Greek
Gujarati Gurmukhi Han Hangul Hanunoo
Hebrew Hiragana Imperial_Aramaic Inherited Inscriptional_Pahlavi
Inscriptional_Parthian Javanese Kaithi Kannada Katakana
Kayah_Li Kharoshthi Khmer Lao Latin
Lepcha Limbu Linear_B Lisu Lycian
Lydian Malayalam Mandaic Meetei_Mayek Meroitic_Cursive
Meroitic_Hieroglyphs Miao Mongolian Myanmar New_Tai_Lue
Nko Ogham Old_Italic Old_Persian Old_South_Arabian
Old_Turkic Ol_Chiki Oriya Osmanya Phags_Pa
Phoenician Rejang Runic Samaritan Saurashtra
Sharada Shavian Sinhala Sora_Sompeng Sundanese
Syloti_Nagri Syriac Tagalog Tagbanwa Tai_Le
Tai_Tham Tai_Viet Takri Tamil Telugu
Thaana Thai Tibetan Tifinagh Ugaritic
Vai Yi

يتطابق التهريب ‎‎‎\X مع كتلة حروف Unicode الموسعة. كتلة الحروف الموسعة هي واحدة أو أكثر من أحرف Unicode التي تتحد لتشكل حرفًا واحدًا. في الواقع، يمكن اعتبار هذا كمكافئ Unicode لرمز النقطة . لأنه سيُطابق حرفًا واحدًا مكونًا، بغض النظر عن عدد الأحرف الفردية المستخدمة فعليًا لعرضه.

مطابقة الأحرف بواسطة خاصية Unicode ليست سريعة، لأن PCRE يجب أن يبحث في بنية تحتوي على بيانات لأكثر من خمسة عشر ألف حرف. لهذا السبب فإن تسلسلات التهريب التقليدية مثل ‎‎‎\d و ‎‎‎\w لا تستخدم خصائص Unicode في PCRE.

المُرتكزات (Anchors)

يعد الرمز ^ خارج فئة الحرف وفي وضع المطابقة الافتراضي، تأكيدًا صحيحًا فقط إذا كانت نقطة المطابقة الحالية في بداية السلسلة النصية الهدف. أما في داخل فئة الحرف، يكون للرمز ^ معنىً مختلفًا تمامًا (انظر أدناه).

لا يجب أن يكون الرمز ^ هو الحرف الأول للنمط إذا كان هناك عدد من البدائل، ولكن يجب أن يكون أول شيء في كل بديل يظهر فيه إذا كان النمط متطابقًا مع ذلك الفرع. إذا كانت جميع البدائل الممكنة تبدأ بالحرف ^، أي إذا كان النمط مقيدًا بحيث لا يتطابق إلا مع بداية السلسلة النصية الهدف، فيقال أنه نمط "مرتكَز" (anchored). (هناك أيضًا بِنىً أخرى يمكن أن تسبب إرتكازًا لنمط ما).

الرمز $ هو تأكيد يصبح TRUE فقط إذا كانت نقطة المطابقة الحالية في نهاية سلسلة الهدف، أو مباشرة قبل حرف السطر الجديد والذي يكون الحرف الأخير في السلسلة (افتراضيًا). لا يلزم أن يكون الرمز $ هو آخر رمز في النمط إذا كان هناك عدد من البدائل، ولكن يجب أن يكون العنصر الأخير في أي فرع يظهر فيه. ليس لرمز $ أي معنىً خاصًا في فئة الحرف.

يمكن تغيير معنى رمز الدولار $ بحيث يتطابق فقط في نهاية السلسلة، وذلك بتعيين الخيار PCRE_DOLLAR_ENDONLY في وقت الترجمة أو المطابقة. ولا يؤثر هذا على التوكيد ‎‎\Z.

يتغير معنى الرمزين ^ و $ إذا ضُبِط الخيار PCRE_MULTILINE. في هذه الحالة، فإنها تتطابق بعد الحرف "‎‎\n" الداخلي مباشرةً وقبله مباشرةً على التوالي وبالترتيب، إضافةً إلى المطابقة في بداية سلسلة الهدف ونهايتها. على سبيل المثال، يطابق النمط ‎/^abc$/‎ السلسلة النصية "‎‎def‎\nabc" في الوضع متعدد الأسطر، ولكنه لا يُطابِقها بخلاف ذلك. وبالتالي، الأنماط التي ترتكز في وضع سطر واحد، لا يمكن أن ترتكز هي نفسها في وضع متعدد الأسطر، وذلك لأن جميع الفروع تبدأ بالرمز "^". ويُتجاهل الخيار PCRE_DOLLAR_ENDONLY إذا ضُبِط الخيار PCRE_MULTILINE.

لاحظ أنه يمكن استخدام التسلسلات ‎‎\A و ‎‎\Z و ‎‎\z لمطابقة بداية ونهاية سلسلة الهدف في كلا الوضعين، وإذا كانت جميع فروع النمط تبدأ بـ ‎‎\A فستكون دائمًا مُرتكِزة، سواءً ضُبطت PCRE_MULTILINE أو لم تضبط.

النقطة (Dot)

خارج فئة الحرف، تتطابق نقطة في النمط مع أي حرف واحد في السلسلة الهدف، بما في ذلك الأحرف غير المطبوعة، ولكن ليس السطر الجديد (افتراضيًا). إذا ضُبط خيار PCRE_DOTALL، فإن النقاط تتطابق مع الأسطر الجديدة أيضًا. يُعد التعامل مع النقطة مستقلاً تمامًا عن التعامل مع كلٍ من الرمزين ^ و $، والعلاقة الوحيدة بينهما هي أن كلاهما يتضمن حروف السطر الجديد. وليس لدى النقطة أي معنى خاص في فئة الحرف.

يمكن استخدام ‎\C لمطابقة البايت المُفرد. من المنطقي في وضع UTF-8 أن تتطابق النقطة مع الحرف بالكامل والذي يمكن أن يتكون من وحدات بايت متعددة.

فئات الحروف (Character Classes)

يُعرِّف قوسُ افتتاح مربع فئةَ الحرف، ويُنهيها بقوسِ إغلاق مربع. ولا يُعد قوس الإغلاق المربع بمفرده حرفًا خاصًا. وإذا كان قوس الإغلاق المربع مطلوبًا كعضو في الفئة، فيجب أن يكون هو أول حرف بيانات في الفئة (بعد أول رمز ^، إذا كان موجودًا) أو إذا كان قد هُرِّب بشرطة مائلة عكسية (Backslash).

تطابق فئةُ الحروف حرفًا واحدًا في السلسلة الهدف؛ ويجب أن يكون الحرف في مجموعة الحروف التي تحددها الفئة، إلا إذا كان الحرف الأول في الفصل هو حرف ^، وفي هذه الحالة يجب ألا يكون الحرف الهدف في المجموعة المُحدَدَة بالفئة. إذا كان هناك حاجة فعلًا إلى وجود الحرف ^ كعضو في الفئة، يجب التأكد من أنه ليس الحرف الأول، أو أنَّه مُهرّب باستخدام شرطة مائلة عكسية.

على سبيل المثال، تتطابق فئة الحرف [aeiou] مع أي حرف متحرك صغير، بينما يتطابق [‎^aeiou] مع أي حرف ليس حرفًا متحركًا صغيرًا. لاحظ أن الرمز ^ هو مجرد طريقة كتابة أكثر ملائمة لتحديد الحروف الموجودة في الفئة عن طريق تعداد الحروف غير الموجودة. وهو ليس تأكيدًا (أي للإشارة إلى بداية السلسلة النصية): فهو لا يزال يستهلك حرفًا من سلسلة الهدف، ويفشل إذا كان المؤشر الحالي في نهاية السلسلة النصية.

عند استخدام المطابقة غير الحساسة لحالة الحروف فإن أي حروف في فئة تمثل كلًا من حالتيها الكبرى والصغرى، فعلى سبيل المثال، المطابقة غير الحساسة للفئة [aeiou] تطابق "A" بالإضافة إلى "a"، والمطابقة غير الحساسة للفئة [‎^aeiou] لا تتطابق مع "A"، في حين أن النسخة الحساسة (caseful) ستطابقه.

لا يمكن التعامل مع حرف السطر الجديد أبدًا بأي طريقة خاصة داخل فئات الحروف، أيا كان إعداد خيارات PCRE_DOTALL أو PCRE_MULTILINE. ستطابق فئة مثل [‎^a] دائمًا سطرًا جديدًا.

يمكن استخدام رمز الشرطة "-" (علامة الطرح) لتحديد مجال من الحروف داخل فئة حروف. على سبيل المثال، يتطابق المجال [d-m] مع أي حرف بدايةً من حرف d ونهايةً بحرف m. إذا كانت هناك حاجة إلى رمز الشرطة - داخل الفئة، فيجب أن تُهرّب باستخدام شرطة مائلة عكسية أو إذا كانت تظهر في موضع لا يمكن تفسيره على أنه يشير إلى نطاق، عادة كحرف أول أو أخير في الفئة.

من غير الممكن أن يكون رمز علامة القوس المربع "‎]‎" هو الحرف الأخير في المجال. يُفسَّر نمط مثل [W-]46] على أنه فئة من حرفين ("W" و "-") متبوعًا بسلسلة حرفية "46‎]‎"، بحيث يتطابق مع "W46" أو "‎‎‎‎-46]‎". ومع ذلك، إذا هُرّبت "‎]‎" باستخدام شرطة مائلة عكسية، فستُفسَّر على أنها نهاية المجال، لذلك تفسّر [W-\]46] كفئة واحدة تحتوي على مجال متبوع بحرفين منفصلين. يمكن أيضًا استخدام التمثيل الثماني أو الست عشري للقوس "‎]‎" لإنهاء المجال.

تعمل المجالات في ترتيب متواليات ASCII. ويمكن أيضًا استخدامها للحروف المحددة رقميًا، على سبيل المثال [‎\000- ‎\037]. إذا اُستخدم المجال الذي يتضمن الحروف عند تعيين المطابقة غير الحساسة لحالة الحروف (caseless)، فإنه يتطابق مع الحروف في كلتا الحالتين. على سبيل المثال، يكافئ المجالُ [Wc] المجالَ [‎\^_'wxyzabc]، ويتطابق مع الحروف بشكل غير حساس لحالتها، وإذا كانت جداول الحروف الخاصة بالمحلية (locale) الفرنسية "fr" قيد الاستخدام، فإن المجال [‎\xc8- ‎\xcb] يتطابق مع أحرف E ذات الحركات (accented) بحالتيها الكبرى والصغرى.

قد تظهر أيضًا أنواع الحروف ‎\d و ‎\D و ‎\s و ‎\S و ‎\w و ‎\W في فئة الحروف وتُضيف الحروف التي تتطابق مع الفئة. على سبيل المثال، يتطابق [‎\dABCDEF] مع أي رقم ست عشري. يمكن بسهولة استخدام رمز ^ مع أنواع الأحرف الكبيرة لتحديد مجموعة أحرف أكثر تقييدًا من أنواع الأحرف الصغيرة المطابقة. على سبيل المثال، تتطابق الفئة [‎^‎\W_‎] مع أي حرف أو رقم، ولكن ليس مع الشرطة السفلية (underscore).

جميع الحروف غير الهجائية الرقمية غير ‎\ و - و ^ (في البداية) و القوس المربع ‎]‎ في النهاية غير مُميَزين في فئات الحروف ولكنها لا تضر إذا هُرِّبت. دائمًا ما تكون نهاية النمط خاصة ويجب أن تُهرب عند استخدامها داخل تعبير.

تدعم لغة Perl مجموعة رموز POSIX لفئات الحروف. وهي تستخدم أسماء محاطة بين [: و :] داخل الأقواس المربعة. وتدعم PCRE أيضًا هذه الرموز. على سبيل المثال، تطابق ‎[01[:alpha:]%]‎ مع "0" أو "1" أو أي حرف هجائي أو رمز "%". أسماء الفئات المدعومة هي:

alnum حروف وأرقام.
alpha حروف.
ascii رموز الحروف 0 - 127.
blank المسافة العادية أو علامة الجدولة فقط.
cntrl حرف التحكم.
digit الأرقام العشرية (مثل ‎\d).
graph حروف الطباعة، باستثناء المسافة العادية.
lower الحروف الصغيرة.
print حروف الطباعة، بما في ذلك المسافة العادية.
punct حروف الطباعة، باستثناء الحروف والأرقام.
space المسافة العادية (ليست مثل ‎\s تمامًا).
upper الحروف الكبيرة.
word الحروف التي يمكن أن تكون موجودة في كلمة (word، مثل ‎\w).
xdigit أرقام ست عشرية.

أحرف المسافة "whitespace" هي HT ‏(horizontal tab، ورمزه 9، وهو مسافة الجدولة الأفقية)‎ و LF ‏(line feed، ورمزه 10، وهو محرف الانتقال إلى سطرٍ جديد)‎ و VT ‏(vertical tab،ورمزه 11، وهو مسافة الجدولة الرأسية)‎ و FF‏ (form feed، ورمزه 12، وهو محرف الانتقال إلى صفحة جديدة)‎ و CR ‏(carriage return، ورمزه 13، وهو محرف العودة إلى بداية السطر)‎ والمسافة العادية (32). لاحظ أن هذه القائمة تتضمن حرف VT ورمزه 11. هذا يجعل "المسافة" مختلفة عن ‎\s، والتي لا تتضمن VT (للتوافق مع Perl).

من الممكن استخدام ميزة النفي والتي يشار إليها بحرف ^ بعد رمز النقطتين ":". على سبيل المثال، يطابق ‎[12[:^digit:]]‎ مع "1" أو "2" أو أي حرف آخر غير رقمي.

التناوب (Alternation)

يُستخدم رمز الشرطة الرأسية للفصل بين الأنماط البديلة. على سبيل المثال، يُطابق النمط gilbert | sullivan إما "gilbert" أو "sullivan". وقد يظهر أي عدد من البدائل، كما يُسمح ببديل فارغ (يطابق سلسلة نصية فارغة). وتحاول عملية المطابقة كل بديل في دوره من اليسار إلى اليمين، ويُستخدم الخيار الأول الذي ينجح. إذا كانت البدائل داخل نمط فرعي، فإن "النجاح" يعني مطابقة بقية النمط الرئيسي بالإضافة إلى البديل في النمط الفرعي.

إعدادات الخيارات الداخلية

يمكن تغيير إعدادات PCRE_CASELESS و PCRE_MULTILINE و PCRE_DOTALL و PCRE_UNGREEDY و PCRE_EXTRA و PCRE_EXTENDED و PCRE_DUPNAMES من داخل النمط باستخدام تسلسل من أحرف الخيارات من لغة Perl بين "(?" و ")". أحرف الخيار هي:

i لضبط PCRE_CASELESS.
m لضبط PCRE_MULTILINE.
s لضبط PCRE_DOTALL.
x لضبط PCRE_EXTENDED.
U لضبط PCRE_UNGREEDY.
X لضبط PCRE_EXTRA.
J لضبط PCRE_INFO_JCHANGED.

ومثال على ذلك: يضبط (‎?im) عدم الحساسية لحالة الحرف (caseless)، ومطابقة متعددة الأسطر. من الممكن أيضًا إلغاء ضبط هذه الخيارات من خلال كتابة الحرف مسبوقًا بعلامة الطرح "-"، بالإضافة إلى تركيبة من ضبط الإعدادات وإلغاء ضبطها مثل (‎?‎im-sx)، والتي تضبط PCRE_CASELESS و PCRE_MULTILINE بينما تلغي ضبط PCRE_DOTALL وتسمح أيضًا بضبط لضبط PCRE_EXTENDED. إذا ظهر الحرف قبل وبعد علامة الطرح، فسيلغى ضبط الخيار.

عندما يحدث تغيير في الخيار في المستوى الأعلى (أي ليس داخل أقواس النمط الفرعي)، ينطبق التغيير على ما تبقى من النمط التالي. لذلك فإن /ab(?i)c/ تطابق فقط "abc" و "abC".

في حالة كان التغيير في الخيار داخل النمط الفرعي، يكون التأثير مختلفًا. وهو تغيير في السلوك في بيرل 5.005. تغيير الخيار داخل نمط فرعي يؤثر فقط على هذا الجزء الذي يتبعه من نفس النمط الفرعي، لذلك (a(?i)b)c) تطابق abc و aBc ولا توجد سلاسل أخرى (بافتراض عدم استخدام PCRE_CASELESS). بهذه الطريقة، يمكن إجراء خيارات مختلفة للحصول على إعدادات مختلفة في أجزاء مختلفة من النمط. أي تغييرات تطرأ على بديل واحد يستمر تأثيرها في الفروع اللاحقة داخل نفس النمط الفرعي. على سبيل المثال، (a(?i)b|c) يتطابق مع "ab" و "aB" و "c" و "C"، على الرغم من أنه عند مطابقة "C" تخلى عن أول فرع قبل ضبط الخيار. هذا لأن تأثيرات ضبط الخيار تحدث في وقت الترجمة. وبخلاف ذلك، سيكون هناك بعض السلوك الغريب جدًا.

يمكن تغيير خيارات PCRE الخاصة PCRE_UNGREEDY و PCRE_EXTRA بنفس الطريقة مثل الخيارات المتوافقة مع Perl باستخدام الأحرف U و X على التوالي. ويُعد ضبط الراية (‎?X) أمرًا خاصًا لأنه يجب أن يأتي دائمًا في النمط قبل ضبط أي خيار إضافي حتى عندما تكون في أعلى مستوى. ومن الأفضل وضعه في البداية.

الأنماط الفرعية (Subpatterns)

تُحدَّد الأنماط الفرعية بواسطة الأقواس (بين قوسين مستديرين)، والتي يمكن أن تكون متداخلة. ويؤدي اعتبار جزء من نمطٍ ما كنمط فرعي إلى أمرين:

  1. تحديد موضع مجموعة من البدائل. على سبيل المثال، يطابق النمط cat(aract|erpillar|)‎ إحدى الكلمات "cat" أو "cataract" أو "caterpillar". والذي يتطابق دون الأقواس مع "cataract" أو "erpillar" أو السلسلة النصية الفارغة.
  2. ضبط النمط الفرعي باعتباره نمطًا فرعيًا لاقطًا (كما هو موضح أعلاه). عندما يتطابق نمط بأكمله، يُعيد هذا الجزء من السلسلة الهدف والذي يطابق النمط الفرعي إلى الدالة المُنادية من خلال الوسيط ovector للدالة pcre_exec‎()‎. وتُحسب الأقواس الافتتاحية من اليسار إلى اليمين (بدءًا من 1) للحصول على أرقام الأنماط الفرعية اللاقطة.

على سبيل المثال، إذا تطابقت سلسلة "the red king" مع النمط ((red|white) (king|queen))، فستكون السلاسل الفرعية المُلتقَطة هي "red king" و "red" و "king"، ومرقمة 1 و 2 و 3.

حقيقة أن الأقواس العادية تحقق وظيفتين ليست دائما مفيدة. غالبًا ما تكون هناك أوقات يكون فيها النمط الفرعي تجميعًا مطلوبًا بدون متطلبات الالتقاط. إذا تبِع قوس الفتح "‎?:‎"، فلن يلتقط النمط الفرعي شيئًا، ولا يُحتسب عند عد أنماط الالتقاط الفرعية اللاحقة. على سبيل المثال، إذا تطابقت السلسلة "the white queen" مع النمط ‎((?:red|white) (king|queen))‎، فإن السلاسل الفرعية الملتقطة هي "white queen" و "queen"، ومرقمة 1 و 2. الحد الأقصى لعدد السلاسل الفرعية المُلتقَطة هو 65535. قد لا يكون من الممكن تصريف مثل هذه الأنماط الكبيرة، ومع ذلك، يعتمد الأمر على خيارات إعدادات مكتبة libpcre.

كاختصار مناسب، إذا كانت هناك حاجة إلى أي إعدادات للخيارات في بداية النمط الفرعي غير اللاقط، قد تظهر أحرف الخيارات بين "?" و ":". وبالتالي فإن النمطين

(?i:saturday|sunday)
(?:(?i)saturday|sunday)

يطابقان بالضبط نفس المجموعة من السلاسل النصية. ويرجع ذلك لأن تجربة الفروع البديلة تبدأ من اليسار إلى اليمين، ولا يُعاد تعيين الخيارات حتى نصل إلى نهاية النمط الفرعي، ولا يؤثر إعداد الخيار في فرع واحد على الفروع التالية، لذلك فإن الأنماط السابقة تتطابق مع "SUNDAY" بالإضافة إلى "Saturday".

من الممكن تسمية النمط الفرعي باستخدام الصياغة ‎(?P<name>pattern)‎. ثم يُفهرس هذا النمط الفرعي في مصفوفة التطابقات بموضعه الطبيعي الرقمي وأيضًا بالاسم. ويقدم PHP 5.2.2 اثنين من الصياغات البديلة ‎(?<name>pattern)‎ و  ‎(?'name'pattern)‎.

من الضروري في بعض الأحيان أن تكون هناك مطابقة متعددة، ولكن يجب أن تكون مجموعات فرعية تبادلية في تعبير نمطي. عادة، كل واحد منها سيحصل على رقمه المرجعي الخلفي (backreference) الخاص به على الرغم من أن واحد منهم فقط قد يكون متطابقًا. وللتغلب على ذلك، تسمح الصيغة ‎(?|‎ بوجود أرقام مكررة. خذ بالحسبان التعبيرات النمطية التالية المطابقة عند محاولة مطابقة السلسلة النصية Sunday:

(?:(Sat)ur|(Sun))day

يُخزَّن Sun في المرجع الخلفي 2، في حين أن المرجع الخلفي 1 يبقى فارغًا. وتخلُف المطابقة Sat في المرجع الخلفي 1 بينما المرجع الخلفي 2 غير موجود. لكن تغيير النمط لاستخدام ‎(?|‎ يصلح هذه المشكلة:

(?|(Sat)ur|(Sun))day

استخدام هذا النمط، سيخزّن كلًا من Sun و Sat في المرجع الخلفي 1.

التكرار (Repetition)

يتحدد التكرار من خلال مُحدِدات كَمّية، والتي يمكن أن تتبع أيًا من العناصر التالية:

  • حرف واحد، وإن كان مُهربًا.
  • الحروف الخاصة.
  • فئة أحرف.
  • مرجع خلفي (انظر القسم التالي).
  • نمط فرعي بين قوسين (ما لم يكن تأكيدًا - انظر أدناه).

ويُحدد مُحدِدُ التكرار العام الكَمّيُ الحدَ الأدنى والحدَ الأقصى لعدد المتطابقات المسموح بها، عن طريق إعطاء الرقمين مفصولَين بفاصلة بين قوسين معقوفين. ويجب أن تكون هذه الأرقام أقل من 65536، وأن يكون الأول أقل من أو يساوي الثاني. على سبيل المثال: z {2,4}‎ يطابق "zz" أو "zzz" أو "zzzz". ولا يُعد قوس الإغلاق حرفًا خاصًا من تلقاء نفسه.

إذا حُذِف الرقم الثاني، وظلت الفاصلة موجودة، فلن يكون هناك حدٌ أعلى؛ أمّا إذا حُذِف كل من الرقم الثاني والفاصلة، يقتصر التكرار على عددٍ دقيقٍ مُحدِّدٍ من التطابقات المطلوبة. وهكذا، فإن ‎[aeiou]{3,}‎ يتطابق مع 3 أحرف متحركة متتالية على الأقل، ولكن قد يتطابق مع أكثر من ذلك، في حين أن ‎\d{8}‎ يتطابق تمامًا مع 8 أرقام. ويُعد قوس الفتح المعقوف كرمز بذاته حرفيًا (literal character) إذا ظهر في موضع لا يسمح فيه بوجود مُحدِدًا كمّيًا، أو إذا لم يتطابق مع صيغة مُحدِدٍ كمّيٍ. على سبيل المثال، {‎,6} ليس مُحدِدًا كميًا، ولكنه سلسلةً نصيةً حرفيةً تتكون من أربعة أحرف.

يُسمح باستخدام المُحدِد الكَمِّي {0}، فيتصرّف التعبير كما لو أن العنصر السابق والمُحدِّد الكمّي غير موجودَين.

تُستخدم المُحدِداتُ الكمّية الثلاثة الأكثر شيوعًا اختصاراتٍ ذات أحرفٍ فرديةٍ للسهولة (والتوافق التاريخي):

* يعادل {‎0,‎}
+ يعادل {‎1,‎}
? يعادل {0,1}

من الممكن إنشاء حلقات لا نهائية باتباع نمط فرعي والذي لا يمكن أن يُطابق أي حرف مع مُحدِدات كَمّية ليس لها حدٌ أعلى، على سبيل المثال: ‎(a?)*‎.

عادة ما تُخرِج الإصدارات السابقة من Perl و PCRE خطأً في وقت الترجمة لمثل هذه الأنماط. ومع ذلك، تُقبل هذه الأنماط الآن نظرًا لوجود حالات يمكن أن يكون فيها هذا مفيدًا، ولكن إذا لم يتطابق أي تكرار لنمطٍ فرعي في الواقع مع أي حرف، فتنكسر الحلقة بالقوة.

تكون المُحدِدات الكَمّي "جشعة" افتراضيًا، أي أنها تتطابق قدر المستطاع (حتى الحد الأقصى لعدد المرات المسموح بها)، دون التسبب في فشل باقي النمط. المثال الكلاسيكي لإمكانية حدوث ذلك، عند محاولة مطابقة التعليقات في برامج C. تظهر هذه بين التسلسلات ‎/*‎ و ‎*/‎ وضمن تسلسل الأحرف * و / الفرديتين. تفشل محاولة لمطابقة التعليقات في لغة C بتطبيق النمط /\*.*\*/ على السلسلة النصية /* first comment */ not comment /* second comment */، لأنه يتطابق مع السلسلة بأكملها بسبب جشع العنصر "*.".

ومع ذلك، إذا تبِعت علامة الإستفهام ? المُحدِدَ الكًمّي، فإنها تصبح "كسولة"، وبدلاً من ذلك تتطابق مع الحد الأدنى لعدد المرات الممكنة، لذلك فإن النمط ‎/\*.*?\*/‎ يعمل مع التعليقات في لغة C بشكل صحيح. ولا يتغير معنى المُحدِدات الكَمّية المختلفة، فقط العدد المفضل من التطابقات. لا تخلط بين هذا الاستخدام لعلامة استفهام وبين استخدامها مُحددًا كَمّيًا بحد ذاتها. لأن لها استخدامَين، يمكن أن تظهر في بعض الأحيان مُضاعَفة، كما هو الحال في ‎\‎d??\d والذي يتطابق مع رقم واحد حسب الأفضلية، ولكن يمكن أن يتطابق مع اثنين إذا كانت هذه هي الطريقة الوحيدة التي يطابق بها باقي النمط.

إذا ضُبط الخيار PCRE_UNGREEDY (وهو خيار غير متوفر في لغة Perl)، فتصبح المحددات الكَمّية غير جشعة افتراضيًا، ولكن يمكن جعلها جشعة بشكل فردي عن طريق اتباعها بعلامة استفهام. بمعنى آخر، فإنه يعكس السلوك الافتراضي.

تُعد المُحدِدات الكمّية التي تتبعها علامة + "تملُّكيَّة". فهي تلتهم أكبر عدد ممكن من الحروف ولا تواصل المطابقة مع بقية النمط. وهكذا يتطابق ‎.*abc مع "aabc" ولكن لا يتطابق ‎.*+abc معه لأن ‎.*+‎ يلتهم السلسلة بأكملها. يمكن استخدام المُحدِدات الكَمّية لتسريع المعالجة.

عند تحديد كمية نمط فرعي مُحاط بقوسين مع حد أدنى للتكرار أكبر من 1 أو بحد أقصى محدود، يلزم مساحة أكبر لتخزين النمط المُترجَم، بما يتناسب مع حجم الحد الأدنى أو الحد الأقصى.

في حالة بدء نمطِ ما بـ ‎.*‎ أو ‎.{0,}‎ وقد ضُبِطَ الخيار PCRE_DOTALL (مكافئ للخيار ‎/s في Perl)، مما يسمح للنقطة "." بأن تتطابق مع السطور الجديدة، ثم يُثبَّت النمط ضمنيًا (implicitly anchored)، نظرًا لأن كل ما يلي سيُختبَر مقابل كل موضع حرف في السلسلة النصية الهدف، لذلك ليس هناك فائدة من إعادة المحاولة الكلية في أي موضع بعد الأول. يعامل PCRE مثل هذا النمط كما لو كانت مسبوقة بـ ‎\A. في الحالات التي يُعرف فيها أن السلسلة النصية الهدف لا تحتوي على سطور جديدة، من الأجدر ضبط PCRE_DOTALL عندما يبدأ النمط بـ ‎.*‎ للحصول على هذا التحسين، أو بدلاً من ذلك، استخدام الرمز ^ للإشارة إلى الإرتكاز صراحةً.

عند تكرار نمط فرعي لاقِط، تكون القيمة الملتقَطة هي السلسلة الفرعية المتطابقة مع التكرار النهائي. على سبيل المثال، بعد تطابق ‎(tweedle[dume]{3}\s*)+‎ مع "tweedledum tweedledee" تكون قيمة السلسلة الفرعية المُلتقَطة هي "tweedledee". ومع ذلك، إذا كانت هناك أنماط فرعية مُلتقِطة متداخلة، فقد تكون القيم المُلتقَطة المقابلة قد ضُبِطت في التكرارات السابقة. على سبيل المثال، بعد تطابق ‎/(a|(b))+/‎ مع "aba" تصبح قيمة السلسلة الفرعية المُلتَقَطة الثانية هي "b".

المراجع الخلفية (Back References)

خارج فئة الحروف، تُعد الشَرطة المائلة العكسية متبوعةً برقم أكبر من 0 (وربما المزيد من الأرقام) هو مرجع خلفي إلى نمطٍ فرعيٍ لاقطٍ سابقٍ (أي إلى اليسار) في النمط، بشرط أن يكون هناك العديد من الأنماط الفرعية التي تسبقه.

ومع ذلك، إذا كان الرقم الذي يتبع الشَرطة المائلة العكسية أقل من 10، فسيُستخدم دائمًا كمرجعٍ خلفيٍ، ويتسبب في حدوث خطأ فقط إذا لم يكن هناك العديد من الأقواس اليسرى في النمط كله. وبعبارة أخرى، لا يجب أن تقع الأقواس المستخدمة كمراجِع إلى يسار المرجع للأرقام الأقل من 10. يمكن أن يكون "المرجع الخلفي المُتقدِّم" منطقيًا عند حدوث التكرار ومشاركة النمط الفرعي إلى اليمين في تكرارٍ سابقٍ. راجع القسم المسمى الشرطة المائلة العكسية "Backslash" للحصول على مزيد من التفاصيل حول التعامل مع الأرقام التي تتبع الشرطة المائلة العكسية.

يتطابق المرجع الخلفي مع أي تطابق فعلي بين النمط الفرعي اللاقط في السلسلة النصية الهدف الحالية، بدلاً من أي شيء يتطابق مع النمط الفرعي نفسه. لذا فإن النمط ‎(sens|respons)e و ‎\1ibility يتطابق مع "sense and sensibility" ومع "response and responsibility"، ولكن ليس مع "sense and responsibility". إذا كانت المطابقة الحساسة لحالة الأحرف سارية المفعول في وقت إجراء المرجع الخلفي، عندئذ تكون حالة الأحرف مهمةً. ومثال على ذلك: يطابق النمط ‎((?i)rah)\s+\1 مع "rah rah" و "RAH RAH"، ولكن ليس "RAH rah"، على الرغم من مطابقة النمط الفرعي الأصلي اللاقط بدون الحساسية لحالة الحرف.

قد يكون هناك أكثر من مرجع خلفي واحد يشير إلى نفس النمط الفرعي. إذا لم يُستخدم بالفعل نمطٌ فرعيٌ في تطابق معين، فستفشل أي مراجع خلفية إليه دائمًا. على سبيل المثال، يفشل النمط ‎(a|(bc))\2 دائمًا إذا بدأ بمطابقة "a" بدلاً من "bc". نظرًا لأنه قد يكون هناك ما يصل إلى 99 مرجعًا خلفيًا، وتؤخذ جميع الأرقام التي تلي الشرطة المائلة العكسية كجزء من رقم مرجع خلفي محتمل. إذا استمر النمط باستخدام حرف رقمي، يجب استخدام بعض المُحدِدات لإنهاء المرجع الخلفي. إذا ضُبط الخيار PCRE_EXTENDED، يمكن أن تكون هذه مسافةً بيضاءً. وإلا يمكن استخدام تعليق فارغ.

يفشل مرجع خلفي يحدث داخل الأقواس التي تشير إليها عندما يُستخدم نمط فرعي لأول مرة، لذلك، على سبيل المثال، (a\1) لا تتطابق أبدًا. ومع ذلك، يمكن أن تكون هذه المراجع مفيدة داخل أنماط فرعية المتكررة. على سبيل المثال، يطابق النمط ‎(a|b\1)+‎ أي عدد من حروف "a" وأيضًا "aba" و "ababba" ...إلخ. في كل تكرار من نمط فرعي، يتطابق المرجع الخلفي مع سلسلة الحروف المقابلة للتكرار السابق. ولكي يعمل هذا بشكل صحيح، يجب أن يكون النمط بحيث لا يحتاج التكرار الأول إلى مطابقة المرجع السابق. ويمكن القيام بذلك باستخدام التناوب، كما هو الحال في المثال أعلاه، أو عن طريق مُحدِد كًمّي مع حد أدنى يساوي الصفر.

يمكن استخدام تسلسل الهروب ‎\g للإحالة المطلقة والنسبية للأنماط الفرعية بدءًا من 5.2.1 من PHP. يجب أن يتبع تسلسل التهريب هذا رقمُ غير مؤشر (unsigned) أو رقم سالب، محاطٌ اختياريًا بالأقواس. السلاسل ‎\1 و ‎\g1 و ‎\g{1}‎ مترادفة مع بعضها بعضًا. يمكن أن يساعد استخدام هذا النمط مع رقم غير مؤشر في إزالة الغموض المتأصل عند استخدام الأرقام بعد الشرطة المائلة العكسية. يساعد التسلسل على تمييز المراجع الخلفية من الحروف الثُمانية، كما يسهل الأمر من وجود مرجع خلفي متبوع برقم حرفي، على سبيل المثال ‎\g{2}1.

يشير استخدام تسلسل ‎\g مع رقم سالب إلى مرجع نسبي. على سبيل المثال، يتطابق ‎(foo)(bar)\g{-1}‎ مع التسلسل "foobarbar" و يتطابق ‎(foo)(bar)\g{-2}‎ مع "foobarfoo". ويمكن أن يفيد هذا في الأنماط الطويلة كبديل لتتبع عدد الأنماط الفرعية من أجل الإشارة إلى نمط فرعي مُحدَد سابقًا.

يمكن تحقيق المراجع الخلفية التي تشير إلى الأنماط الفرعية المُسماه بواسطة (‎?P=name) أو أيضًا بواسطة ‎‎\k<name>‎ أو ‎\k'name' منذ الإصدار PHP 5.2.2. بالإضافة إلى ذلك، أضافت لغة PHP 5.2.4 دعمًا لـ ‎\k{name}‎ و ‎\g{name}‎، و PHP 5.2.7 حتى ‎\g<name>‎ و ‎\g'name'‎.

التأكيدات (Assertions)

التوكيد هو اختبار يُجرى على الأحرف التالية لنقطة المطابقة الحالية أو السابقة لها والذي لا يستنفد فعليًا أي حروف. وتوصف التأكيدات البسيطة التي رُمِّزت مثل ‎\b و ‎\B و ‎\A و ‎\Z و ‎\z و ^ و $ في صفحة تسلسلات التهريب. تُرمَّز التأكيدات الأكثر تعقيدًا كأنماطٍ فرعية. وهناك نوعان: تلك التي تبحث فيما بعدها (look ahead) من الموضع الحالي في السلسلة النصية الهدف، وتلك التي تبحث فيما قبلها (look behind).

يُطابَق نمط التوكيد الفرعي بالطريقة العادية، إلا أنه لا يتسبب في تغيير موضع المُطابقة الحالي. تبدأ تأكيدات البحث الأمامية lookahead بـ ‎(?=‎ للتأكيدات الإيجابية و ‎(?!‎ للتأكيدات السلبية. على سبيل المثال، يتطابق ‎\w+(?=;)‎ مع كلمة متبوعة بفاصلة منقوطة، لكن لا تتضمن الفاصلة المنقوطة في المطابقة، ويتطابق foo‎(?!bar)‎ مع أي تواجد للنمط "foo" لا يتبعه النمط "bar". لاحظ أن نمط مماثل ظاهريًا ‎(?!foo)bar لا يعثر على تواجد للنمط "bar" الذي يسبقه شيء آخر غير "foo"؛ فيجد أي تواجد للنمط "bar" أيًا كان، لأن التوكيد ‎(?!foo)‎ دائمًا TRUE عندما تكون الأحرف الثلاثة التالية هي "bar". ولعلاج هذا التأثير نحتاج إلى استخدام تأكيد البحث الخلفي lookbehind.

تبدأ التأكيدات الخلفية بـ ‎(?<=‎ للتأكيدات الإيجابية و ‎(?<!‎ للتأكيدات السلبية. ومثال على ذلك: لا يعثر النمط ‎(?<!foo)bar على تواجد للنمط "bar" لا يسبقه النمط "foo". وتُقيّد محتويات تأكيد البحث الخلفي lookbehind بحيث يكون لكل السلاسل النصية التي تطابقها طول ثابت. ومع ذلك، إذا كان هناك العديد من البدائل، فلا يجب أن يكون لها جميعًا نفس الطول الثابت. وهكذا فإنه يُسمح بالنمط ‎(?<=bullock|donkey)‎، ولكن يسبب النمط ‎(?<!dogs?|cats?)‎ خطأً في وقت التصريف. لا يُسمح بالفروع التي تتطابق مع السلاسل النصية بأطوال مختلفة إلا في المستوى الأعلى لتأكيدات البحث الأمامية. ويُعد اضافةً مقارنةً بلغة Perl 5.005، الأمر الذي يتطلب أن تطابق جميع الفروع نفس طول السلسلة النصية. غير مسموح بتأكيدٍ مثل ‎(?<=ab(c|de))‎ نظرًا لأن فرع المستوى الأعلى منه الوحيد يمكن أن يتطابق مع طولين مختلفين، ولكن من المقبول أن تُعاد الكتابة لاستخدام فرعين من المستوى الأعلى: ‎(?<=abc|abde)‎ وتُطبَّق التأكيدات الخلفية lookbehind لكل بديل بتحريك الموضع الحالي للخلف مؤقتًا بمقدار عرض ثابت ثم محاولة المطابقة. إذا لم يكن هناك عددٍ كافٍ من الحروف قبل الموضع الحالي، فستعدّ المطابقةُ فاشلةً. يمكن أن تكون تأكيدات البحث الخلفية المقترنة مع الأنماط الفرعية الموجودة مرة واحدة فقط مفيدة بشكل خاص في المطابقة عند نهايات السلاسل النصية؛ ويوجد مثال في نهاية القسم على الأنماط الفرعية الموجودة مرة واحدة فقط.

قد تحدث عدة تأكيدات (من أي نوع) على التوالي. ومثال على ذلك: يتطابق النمط ‎(?<=\d{3})(?<!999)foo مع "foo" المسبوق بثلاثة أرقام ليست "999". لاحظ أن كل التأكيدات تُطبَّق بشكل مستقل في نفس النقطة داخل السلسلة النصية الهدف. أولاً، يتحقق النمط من أن الأحرف الثلاثة السابقة كلها أرقام، ثم يتحقق من أن الأحرف الثلاثة نفسها ليست "999". ولا يتطابق هذا النمط مع "foo" المسبوقة بستة حروف، أولها أرقام وأخر ثلاثة منها ليست "999". على سبيل المثال، هو لا يطابق "123abcfoo". وهناك نمط للقيام بذلك هو ‎(?<=\d{3}...)(?<!999)foo.

في هذه المرة، يظهر التأكيد الأول في الأحرف الستة السابقة، ويتحقق من أن الثلاثة الأولى هي أرقام، ثم يتحقق التأكيد الثاني من أن الأحرف الثلاثة السابقة ليست "999".

يمكن أن تتداخل التأكيدات بأي تركيبات. ومثال على ذلك: يتطابق النمط ‎(?<=(?<!foo)bar)baz مع ظهور النمط "baz" الذي يسبقه النمط "bar" والذي بدوره لا يسبقه النمط "foo"، بينما يتطابق نمطٌ آخر هو ‎(?<=\d{3}...(?<!999))foo مع "foo" المسبوق بثلاثة أرقام وأية ثلاثة أحرف ليست "999".

لا تلتقط أنماطُ التأكيد الفرعية أنماطًا فرعية، وقد لا تتكرر، لأنه لا معنى لتأكيد نفس الشيء عدة مرات. إذا كان أي نوع من التأكيدات يحتوي داخله على أنماطٍ فرعيةٍ لاقطة، فستُحسَب بغرض ترقيم الأنماط الفرعية اللاقطة في النمط بأكمله. ومع ذلك، يُنفّذ التقاط السلاسل النصية الفرعية فقط مع التأكيدات الإيجابية، لأنه لا معنى له مع التأكيدات السلبية.

يُسمح بتعدُد التأكيدات بحد أقصى 200 نمطًا فرعيًا.

الأنماط الفرعية المستخدمة مرة واحدة فقط (Once-​only subpatterns)

مع كلٍ من زيادة التكرار أو تقليله إلى الحدين الأقصى والأدنى، يؤدي فشل ما يلحق عادةً إلى إعادة تقييم العنصر المكرر لمعرفة ما إذا كان هناك عدد مختلف من التكرارات يسمح بمطابقة باقي النمط. في بعض الأحيان يكون من المفيد منع هذا من الحدوث، إما لتغيير طبيعة المُطابقة، أو لإخفاقها في وقت مبكِّر عما قد يحدث خلاف ذلك، وذلك عندما يعلم مؤلف النمط أنه لا فائدة من الاستمرار في ذلك.

على سبيل المثال، تأمل النمط ‎\d+foo عند تطبيقه على سلسلة الهدف 123456bar.

بعد مطابقة جميع الأرقام الستة ثم فشل مطابقة "foo"، يكون الإجراء المعتاد للمُطابق هو إعادة المحاولة باستخدام 5 أرقام فقط تتطابق مع العنصر ‎‎\d+‎، ثم مع 4 أرقام وما إلى ذلك، قبل الفشل في النهاية. توفر الأنماط الفرعية المستخدمة مرة واحدة فقط وسائل لتحديد أنه بمجرد مطابقة جزء من هذا النمط، لا يجب إعادة تقييمه بهذه الطريقة، لذلك فإن المُطابق سوف يتخلى على الفور عند الفشل في مطابقة "foo" في المرة الأولى. الصيغة المستخدمة هي نوع آخر من الأقواس الخاصة، تبدأ بـ ‎(?>‎ كما في هذا المثال: ‎(?>\d+)bar‎.

هذا النوع من الأقواس "يغلق" الجزء من النمط الذي يحويه بمجرد مطابقته، ويمنع الفشل في هذا النمط عن التراجع عنه. ومع ذلك، فإن التراجع المار به إلى العناصر السابقة يعمل بشكل طبيعي.

بطريقة أخرى، النمط الفرعي من هذا النوع يطابق سلسلة الحروف التي يتطابق معها نمط مماثل مستقل بذاته، إذا كان مثبتًا في النقطة الحالية في السلسلة الهدف.

ولا تُعد الأنماط الفرعية المستخدمة مرة واحدة فقط أنماطًا فرعية لاقطة. ويمكن اعتبار الحالات البسيطة مثل المثال أعلاه بمثابة تكرار مكبّر يجب أن يبتلع كل ما في وسعه. إذن، في حين أن كلًا من ‎\d+‎ و ‎\d+?‎ مستعدان لضبط عدد الأرقام التي يطابقونها من أجل جعل بقية النمط متطابقًا، لا يمكن أن يتطابق ‎(?>\d+)‎ إلا مع سلسلة كاملة من الأرقام.

يمكن لهذا البناء بالطبع أن يحتوي على أنماطٍ فرعية عشوائية معقدة، ويمكن أن تكون متداخلة.

كما يمكن استخدام الأنماط الفرعية المستخدمة مرة واحدة فقط تزامنًا مع تأكيدات البحث الخلفية لتحديد مطابقة فعالة في نهاية سلسلة الهدف. تأمل نمطًًا بسيطًًا مثل $abcd عند تطبيقه على سلسلة نصية طويلة لا تتطابق. نظرًا لأن المطابقة تبدأ من اليسار إلى اليمين، سيبحث PCRE عن كل حرف "a" في السلسلة الهدف ثم يرى ما إذا كان ما يلي يطابق بقية النمط. إذا حُدد النمط ‎^.*abcd$‎ ثم طابق ‎.*‎ الأول مع السلسلة بأكملها في البداية، ولكن عندما يفشل هذا (نظرًا لعدم وجود أي حرف "a" تالي)، فإنه يتراجع لمطابقة الكل ما عدا الحرف الأخير، ثم الكل ما عدا آخر حرفين، وهكذا. ومرة أخرى، يغطي البحث عن "a" السلسلة بأكملها، من اليمين إلى اليسار، وهم الحل الأفضل. ومع ذلك، إذا كُتِب النمط كـ ‎^(?>.*)(?<=abcd)‎ ثم لا يمكن أن يكون هناك تراجع عن العنصر ‎*. ويمكن أن يتطابق فقط مع السلسلة بأكملها. يقوم تأكيد البحث الخلفي اللاحق بإجراء اختبار واحد على الأحرف الأربعة الأخيرة. إذا فشل، تفشل المطابقة على الفور. بالنسبة للسلاسل الطويلة، فإن هذا النهج يحدث اختلافًا كبيرًا في وقت المعالجة.

عندما يحتوي نمط ما على تكرار غير محدود داخل نمط فرعي يمكن أن يتكرر بحد ذاته لعدد غير محدود من المرات، فإن استخدام النمط الفرعي المستخدم مرة واحدة فقط هو الطريقة الوحيدة لتجنب فشل بعض المطابقات التي تستغرق وقتًا طويلاً بالفعل. يطابق النمط ‎(\D+|<\d+>)*[!?]‎ عددًا غير محدود من السلاسل الفرعية إما أن تكون غير رقمية، أو رقمية محاطة بين <>، ومتبوعة إما بالرمز ! أو ?. وعندما يتطابق، فإنه يعمل بسرعة. ومع ذلك، إذا طُبِّق على السلسلة النصية aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa يستغرق وقتًا طويلًا قبل الإبلاغ عن الفشل. ويرجع ذلك إلى أن السلسلة يمكن تقسيمها بين التكرارين بعدد كبير من الطرق، ويجب أن تُجرَّب كلها. (استخدم المثال السابق العنصر ‎[!?]‎ بدلًا من حرف واحد في النهاية، لأن كل من PCRE و Perl لهما تحسين يسمح بفشل سريع عند استخدام حرف واحد. ويتذكَّران الحرف المُفرد الأخير المطلوب للمطابقة، ويفشلان مبكرًا إذا لم يكن موجودًا في السلسلة.) إذا تغيَّر النمط إلى ‎((?>\D+)|<\d+>)*[!?]‎ لا يمكن كسر التسلسلات غير الرقمية، والفشل يحدث بسرعة.

الأنماط الفرعية الشرطية (Conditional subpatterns)

من الممكن أن تتسبب عملية المطابقة في الامتثال لنمطٍ فرعي بشكل مشروط أو الاختيار بين نمطين فرعيين بديلين، اعتمادًا على نتيجة التأكيد، أو ما إذا كان نمطٌ فرعي لاقط سابق مطابقًا أم لا. الصورتان الممكنتان من الأنماط الفرعية الشرطية هما:

(?(condition)yes-pattern)
(?(condition)yes-pattern|no-pattern)

إذا أُستُوفي الشرط، يُستخدم نمط الإيجاب (yes-pattern). خلاف ذلك يُستخدم استخدام نمط النفي (no-pattern) (إذا كان موجودًا). إذا كان هناك أكثر من بديلين في النمط الفرعي، يحدث خطأ في وقت الترجمة. هناك نوعان من الشروط. إذا كان النص بين الأقواس يتكون من سلسلة من الأرقام، عندها يُستوفى الشرط إذا كان النمط الفرعي اللاقط لهذا الرقم قد تطابق مسبقًا. في النمط التالي، الذي يحتوي على مسافات بيضاء ليجعله مقرؤًا بشكل أفضل (مُفترض الخيار PCRE_EXTENDED) وتقسيمه إلى ثلاثة أجزاء لسهولة المناقشة:

( \( )?    [^()]+ (?(1) \) )

الجزء الأول يتطابق مع قوس فتح اختياري، وإذا كان هذا الحرف موجودًا، فيُعيّنه كأول سلسلة فرعية مُلتقَطة. الجزء الثاني يتطابق مع واحد أو أكثر من الأحرف التي ليست أقواسًا. الجزء الثالث هو النمط الفرعي الشرطي الذي يختبر ما إذا كانت المجموعة الأولى من الأقواس متطابقة أم لا. إذا تطابقت، وكانت سلسلة الهدف تبدأ بقوس فتح، يكون الشرط TRUE، وبالتالي يُنفذ yes-pattern ثم يقفل بقوس إغلاق. خلاف ذلك، بما أنه لا يوجد نمط no-pattern، لا يطابق النمط الفرعي أي شيء. بمعنى آخر، يطابق هذا النمط تسلسلًا من غير الأقواس، محصورًا بشكل اختياري بين قوسين.

إذا كان الشرط هو السلسلة النصية (R)، يكون مستوفيًا إذا جرى استدعاء متكرر للنمط أو للنمط الفرعي. ويكون الشرط غير صحيح في "المستوى الأعلى".

إذا لم يكن الشرط عبارة عن سلسلة من الأرقام أو (R)، فيجب أن يكون تأكيدًا. وقد يكون تأكيد بحث أمامي (lookahead) أو خلفي (lookbehind) وقد يكون موجبًا أو سالبًا. تأمل هذا النمط، مرة أخرى وهو يحتوي على مسافات بيضاء، ومع الخيارين في السطر الثاني:

(?(?=[^a-z]*[a-z])
\d{2}-[a-z]{3}-\d{2}  | \d{2}-\d{2}-\d{2} )

الشرط هو تأكيد lookahead موجب ويتطابق مع تسلسل اختياري من غير الحروف متبوعًا بحرف. وبعبارة أخرى، فإنه يختبر وجود حرف واحد على الأقل في السلسلة الهدف. فإذا عثر على حرف، يُطابق الهدف مع البديل الأول. وخلاف ذلك يُطابق مع البديل الثاني. يطابق هذا النمط السلاسل النمطية في أحد النموذجين dd-aaa-dd أو dd-dd-dd، حيث aaa حروف و dd أرقام.

التعليقات (Comments)

التركيب ‎(?#‎ يشير إلى بداية تعليق يستمر حتى أقواس الإغلاق التالية. ولا يُسمح بالأقواس المتداخلة. لا تلعب الحروف التي تُشكِّل تعليقًا أي دور في مطابقة النمط على الإطلاق.

إذا ضُبط الخيار PCRE_EXTENDED، يُقدم رمز # (دون تهريبه) الموجود خارج فئة الأحرف تعليقًا يستمر حتى يصل إلى حرف السطر الجديد التالي في النمط.

الأنماط المتكررة (Recursive patterns)

تأمل مشكلة مُطابقة سلسلة نصية بين قوسين مع السماح بوجود أقواس متداخلة غير محدودة. أفضل ما يمكن القيام به دون استخدام التكرارية (recursion)، هو استخدام نمط يتطابق مع عمق تداخلٍ ما ثابت. ولا يمكن التعامل مع عمق تداخل عشوائي. وقد قدمت لغة Perl 5.6 إمكانية تجريبية تسمح بالتعبيرات النمطية بالتكرار (من بين أشياء أخرى). وقدمت العنصر الخاص (?R) لحالة التكرار تحديدًا. يحل نمط PCRE التالي مشكلة الأقواس (تفترض ضبط الخيار PCRE_EXTENDED بحيث يتجاهل المسافات البيضاء): ‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎\( ( (?>[^()]+) | (?R) )* \)‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎‎

أولًا يتطابق النمط مع فتح القوس. ثم يتطابق مع أي عدد من السلاسل الفرعية التي يمكن أن تكون إما تسلسلًا من غير الأقواس، أو تطابقًا متكرراً للنمط نفسه (أي سلسلة فرعية أقواسها صحيحة). وأخيراً هناك قوس إغلاق.

يحتوي هذا المثال الخاص للنمط على تكرارات غير محدودة متداخلة، وبالتالي فإن استخدام نمط فرعي مستخدم مرة واحدة فقط (once-only) لمطابقة سلاسل بدون أقواس هو أمر هام عند تطبيق النمط على سلاسل لا تتطابق. على سبيل المثال، عند تطبيقه على ‎(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()‎ فإنه يُخرِج "لا تطابق (no match)" بسرعة. ومع ذلك، إذا لم يُستخدم نمط فرعي يستخدم مرة واحدة فقط، فستستمر المطابقة لفترة طويلة جدًا، نظرًا لأن هناك العديد من الطرق المختلفة التي يمكن أن يؤدي بها تكرار + و * إلى تآكل الهدف، ويجب عليه اختبار كل شيء قبل الإبلاغ عن الفشل.

القيم المحددة لأي أنماط فرعية لاقطة هي تلك القيم من المستوى الخارجي للتكرار الذي يُعيَّن فيه قيمة النمط الفرعي. إذا تطابق النمط الأعلى مع (ab (cd) ef)، فإن قيمة أقواس الالتقاط هي "ef"، وهي القيمة الأخيرة التي تُلتقط في المستوى الأعلى. إذا أُضيفت أقواس إضافية، مع إعطاء النمط ‎\( ( ( (?>[^()]+) | (?R) )* ) \)‎ فإن السلسلة التي يلتقطونها هي "ab (cd) ef"، وهي محتويات الأقواس ذات المستوى الأعلى. إذا كان هناك أكثر من 15 قوسًا لاقطًا في نمطٍ ما، فيجب أن يحصل PCRE على ذاكرة إضافية لتخزين البيانات أثناء التكرار، وذلك باستخدام pcre_malloc، ويحررها باستخدام pcre_free بعد ذلك. إذا لم يكن من الممكن الحصول على ذاكرة، فستُحفظ البيانات لأقواس الالتقاط الخمسة عشرة الأولى فقط، حيث لا توجد طريقة لإصدار خطأ نفاد الذاكرة (out-of-memory) أثناء التكرار.

يمكن أيضًا استخدام ‎(?1)‎ و ‎(?2)‎ وهكذا للأنماط الفرعية المتكررة. من الممكن أيضا استخدام الأنماط الفرعية المُسماة: ‎(?P>name)‎ أو ‎(?&name)‎.

إذا اُستخدِمت صيغة مرجع نمط فرعي متكرر (إما عن طريق الرقم أو بالاسم) خارج الأقواس التي تشير إليها، فإنها تعمل مثل روتين فرعي في لغة البرمجة. وأشار مثال سابق إلى أن النمط ‎(sens|respons)e and \1ibility يتطابق مع "sense and sensibility" و "response and responsibility", ولكن ليس مع "sense and responsibility". إذا أُستُخدِم بدلًا من ذلك النمط ‎(sens|respons)e and (?1)ibility، فسيتطابق مع "sense and responsibility" فضلًا عن السلسلتين الأخرتين. ومع ذلك، يجب أن تتبع مثل هذه المراجع النمط الفرعي التي تشير إليه.

الحد الأقصى لطول السلسلة الهدف هو أكبر رقم موجب يمكن أن يحتفظ به متغير من النوع "عدد صحيح". ومع ذلك، يستخدم PCRE التكرارية للتعامل مع الأنماط الفرعية اللا نهائية. الأمر الذي يعني أن مساحة المكدس (stack) المتوفرة قد تحد من حجم السلسلة الهدف التي يمكن معالجتها بواسطة أنماط معينة.

‎الأداء (Performance)

تكون بعض العناصر التي قد تظهر في الأنماط أكثر كفاءة من غيرها. ومن الأكثر كفاءة استخدام فئة أحرف مثل [aeiou] عن مجموعة من البدائل مثل (a|e|i|o|u). وبشكل عام، يكون أبسط بناء يوفر السلوك المطلوب هو الأكثر كفاءة. ويحتوي كتاب جيفري فريدل (Jeffrey Friedl) على الكثير من النقاش حول تحسين التعبيرات النمطية للحصول على أكفأ أداء.

عند بدء نمط بالعنصر ‎.*‎ مع ضبط خيار PCRE_DOTALL يرتكز النمط ضمنيًا بواسطة PCRE، نظرًا لأنه يمكن أن يتطابق فقط في بداية سلسلة الهدف. ومع ذلك، إذا لم يُضبط PCRE_DOTALL، لا يمكن لـ PCRE إجراء هذا التحسين، لأن النقطة "." وهي حرف خاص لا تتطابق مع السطر الجديد، وإذا كانت سلسلة الهدف تحتوي على أسطر جديدة، فقد يتطابق النمط مع الحرف الذي يتبع أحدها مباشرةً بدلاً من بداية سلسلة الهدف. على سبيل المثال، يطابق النمط ‎(.*) second سلسلة الهدف "first\nand second" (حيث ‎\n يرمز إلى حرف السطر الجديد) مع أول سلسلة فرعية التقطها "and". وللقيام بذلك، يجب على PCRE إعادة محاولة بدء المطابقة بعد كل سطر جديد في سلسلة الهدف.

إذا كنت تستخدم مثل هذا النمط مع سلاسل الهدف النصية التي لا تحتوي على أسطرٍ جديدة، فسيتحقق أفضل أداء عن طريق ضبط PCRE_DOTALL، أو بدء النمط بالعنصر ‎^.*‎ للإشارة إلى الارتكاز الصريح. ويحفظ هذا PCRE من الاضطرار إلى مسح سلسلة الهدف بطولِها بحثًًا عن سطر جديد لإعادة بدء البحث من عنده.

يجب الحذر من الأنماط التي تحتوي على تكرارات متداخلة غير محدودة. لأنها تستغرق وقتًا طويلاً للتشغيل عند تطبيقها على سلسلة نصية لا تتطابق. تأمل هذا الجزء من النمط ‎(a+)*‎ والذي يمكن أن يتطابق مع "aaaa" بـ 33 طريقة مختلفة، ويزداد هذا العدد بسرعة كبيرة مع زيادة طول السلسلة. (يمكن أن يتطابق التكرار * مع 0 أو 1 أو 2 أو 3 أو 4 مرات، ولكل من تلك الحالات غير 0، يمكن أن يتطابق التكرار + مع عدد مختلف من المرات). عندما يكون المتبقي من النمط بحيث تفشل المطابقة بأكملها، فإن لدى PCRE مبدأ تجربة كل التغييرات الممكنة، ويمكن أن يستغرق هذا وقتًا طويلاً للغاية.

يتحقق التحسين من بعض الحالات الأكثر بساطة مثل ‎(a+)*b حيث يتبعه حرفٌ بذاته حرفيًا (literal). قبل الشروع في إجراء المطابقة القياسية، يتحقق PCRE من وجود حرف "b" لاحقًا في سلسلة الهدف، وفي حالة عدم وجوده، فإنه يُفشِل المطابقةَ على الفور. ومع ذلك، عند عدم وجود الحرف بذاته حرفيًا فيما يلي، لا يمكن استخدام هذا التحسين. يمكن رؤية الفرق بمقارنة سلوك ‎(a+)*\d مع النمط أعلاه. ويفشل الأول على الفور تقريبًا عند تطبيقه على سطر كامل من الأحرف "a"، بينما يأخذ الأخير وقتًا مناسبًا مع سلاسل أطول من 20 حرفًا تقريبًا.

مصادر