Sometimes we need to find only those matches for a pattern that are followed or preceded by another pattern.
هناك صيغة خاصة لذلك ، تسمى “lookahead” و “lookbehind” ، يشار إليها معًا باسم “lookaround”.
في البداية ، دعنا نجد السعر من السلسلة مثل الموضوع: 1 ديك رومي يكلف 30 يورو
. أي: رقم متبوعًا بعلامة €
.
Lookahead
الصيغة هي: X (؟ = Y)
، وتعني "ابحث عن X
، لكن تطابق فقط إذا تبعها "pattern: Y". قد يكون هناك أي نمط بدلاً من
pattern:Xو
pattern:Y`.
بالنسبة لرقم صحيح متبوعًا بـ€
, سيكون regexp
\d+(?=€)
:
let str = '1 turkey costs 30€';
alert(str.match(/\d+(?=€)/)); // 30, the number 1 is ignored, as it's not followed by €
يرجى ملاحظة: lookahead هو مجرد اختبار ، ومحتويات "نمط قوسين: (؟ = …)غير مدرجة في النتيجة
match:30`.
عندما نبحث عن "pattern: X (؟ = Y)` ، يعثر محرك التعبير العادي على “pattern: X” ثم يتحقق مما إذا كان هناك “pattern: Y” بعده مباشرة. إذا لم يكن الأمر كذلك ، يتم تخطي المطابقة المحتملة ، ويستمر البحث.
من الممكن إجراء اختبارات أكثر تعقيدًا ، على سبيل المثال النمط: X (؟ = Y) (؟ = Z)
يعني:
- ابحث عن
النمط: X
. - تحقق مما إذا كان “النمط: Y” مباشرةً بعد “النمط: X” (يمكنك التخطي إذا لم يكن كذلك).
- تحقق مما إذا كان “النمط: Z” هو أيضًا مباشرةً بعد “النمط: X” (يمكنك التخطي إذا لم يكن كذلك).
- في حالة اجتياز كلا الاختبارين ، فإن “النمط: X” هو تطابق ، وإلا فتابع البحث.
بمعنى آخر ، يعني هذا النمط أننا نبحث عن X
متبوعًا بـ Y
و Z
في نفس الوقت.
هذا ممكن فقط إذا كان النموذجان “pattern: Y” و “pattern: Z” لا يستبعد أحدهما الآخر.
على سبيل المثال ، \ d + (؟ = \ s) (؟ =. * 30)
يبحث عن \ d +
فقط إذا كان متبوعًا بمسافة ، ويوجد 30
في مكان ما بعده:
For example, \d+(?=\s)(?=.*30)
looks for \d+
that is followed by a space (?=\s)
, and there’s 30
somewhere after it (?=.*30)
:
let str = '1 turkey costs 30€';
alert(str.match(/\d+(?=\s)(?=.*30)/)); // 1
في سلسلتنا التي تتطابق تمامًا مع الرقم 1
.
Negative lookahead
لنفترض أننا نريد كمية بدلاً من ذلك ، وليس سعرًا من نفس السلسلة. هذا رقم نمط: \ d +
، وليس متبوعًا بـ الموضوع: €
.
لذلك ، يمكن تطبيق lookahead سلبي.
الصيغة هي: X (؟! Y)
، وتعني "search X
، ولكن فقط إذا لم يتبعها “pattern: Y`”.
let str = '2 turkeys cost 60€';
alert(str.match(/\d+\b(?!€)/g)); // 2 (the price is not matched)
Lookbehind
يسمح Lookahead بإضافة شرط لـ “ما يلي”.
Lookbehind مشابه ، لكنه يبدو في الخلف. أي أنه يسمح بمطابقة النمط فقط إذا كان هناك شيء قبله.
الصيغة هي:
- نظرة إيجابية خلف:
(؟ <= Y) X
، تطابقX
، ولكن فقط في حالة وجود "pattern: Y` قبلها. - مظهر سلبي خلف:
(؟ <! Y) X
، يطابقX
، ولكن فقط في حالة عدم وجودY
قبله.
على سبيل المثال ، دعنا نغير السعر إلى الدولار الأمريكي. عادةً ما تكون علامة الدولار قبل الرقم ، لذلك للبحث عن $ 30
، سنستخدمالنمط: (؟ <= \ $) \ d +
- مبلغ يسبقه
الموضوع: $`:
let str = '1 turkey costs $30';
// the dollar sign is escaped \$
alert(str.match(/(?<=\$)\d+/)); // 30 (skipped the sole number)
وإذا احتجنا إلى الكمية – رقمًا ، لا يسبقه "الموضوع: $، فيمكننا استخدام النمط السلبي خلف ": (؟ <! \ $) \ d +
:
let str = '2 turkeys cost $60';
alert(str.match(/(?<!\$)\b\d+/g)); // 2 (the price is not matched)
التقاط المجموعات
بشكل عام ، لا تصبح المحتويات الموجودة داخل الأقواس حول جزء من النتيجة.
على سبيل المثال في النموذج \ d + (؟ = €)
، لا يتم التقاط علامة €
كجزء من المباراة. هذا طبيعي: نحن نبحث عن رقم نقش: \ d +
، بينما نقش: (؟ = €)
هو مجرد اختبار يجب أن يتبعه الموضوع: €
.
ولكن في بعض المواقف ، قد نرغب في التقاط تعبير lookaround أيضًا ، أو جزء منه. أن من الممكن. ما عليك سوى لف هذا الجزء بأقواس إضافية.
في المثال أدناه ، تم تسجيل “نمط علامة العملة: (€ | kr)” ، بالإضافة إلى المبلغ:
let str = '1 turkey costs 30€';
let regexp = /\d+(?=(€|kr))/; // extra parentheses around €|kr
alert(str.match(regexp)); // 30, €
وإليك نفس الشيء بالنسبة إلى: lookbehind:
let str = '1 turkey costs $30';
let regexp = /(?<=(\$|£))\d+/;
alert(str.match(regexp)); // 30, $
ملخص
Lookahead و lookbehind (يشار إليهما عادةً باسم “lookaround”) مفيدان عندما نرغب في مطابقة شيء ما اعتمادًا على السياق قبله / بعده.
بالنسبة إلى regexps البسيطة ، يمكننا القيام بنفس الشيء يدويًا. هذا هو: مطابقة كل شيء ، في أي سياق ، ثم التصفية حسب السياق في الحلقة.
تذكر أن str.match
(بدون العلامة g
) و str.matchAll
(دائمًا) ترجع التطابقات كمصفوفات مع خاصيةindex
، حتى نعرف مكانها بالضبط في النص ، ويمكننا التحقق من سياق الكلام.
لكن بشكل عام يكون البحث أكثر ملاءمة.
أنواع Lookaround:
النمط | النوع | التطابق |
---|---|---|
X(?=Y) |
Positive lookahead | X إذا تبعه Y |
X(?!Y) |
Negative lookahead | ``pattern: Xإذا لم يتبعه pattern: Y` |
(?<=Y)X |
Positive lookbehind | X إذا بعده Y |
(?<!Y)X |
Negative lookbehind | X إذا لم يكن بعده Y |
التعليقات
<code>
، وللكثير من السطور استخدم<pre>
، ولأكثر من 10 سطور استخدم (plnkr, JSBin, codepen…)