Skip to content

Commit 640a8e9

Browse files
committed
Lookahead and lookbehind regex
1 parent 91dd143 commit 640a8e9

5 files changed

Lines changed: 76 additions & 74 deletions

File tree

9-regular-expressions/14-regexp-lookahead-lookbehind/1-find-non-negative-integers/solution.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11

2-
The regexp for an integer number is `pattern:\d+`.
2+
regexp لرقم صحيح هو `pattern: \ d +`.
33

4-
We can exclude negatives by prepending it with the negative lookahead: `pattern:(?<!-)\d+`.
4+
يمكننا استبعاد السلبيات عن طريق إلحاقها بالمظهر السلبي: `pattern: (؟ <! -) \ d +`.
55

6-
Although, if we try it now, we may notice one more "extra" result:
6+
على الرغم من أننا إذا جربناها الآن ، فقد نلاحظ نتيجة "إضافية" أخرى:
77

88
```js run
99
let regexp = /(?<!-)\d+/g;
@@ -13,11 +13,11 @@ let str = "0 12 -5 123 -18";
1313
console.log( str.match(regexp) ); // 0, 12, 123, *!*8*/!*
1414
```
1515

16-
As you can see, it matches `match:8`, from `subject:-18`. To exclude it, we need to ensure that the regexp starts matching a number not from the middle of another (non-matching) number.
16+
كما ترون ، فإنه يطابق `المباراة: 8` ، من` الموضوع: -18`. لاستبعاده ، نحتاج إلى التأكد من أن regexp يبدأ في مطابقة رقم ليس من منتصف رقم آخر (غير مطابق).
1717

18-
We can do it by specifying another negative lookbehind: `pattern:(?<!-)(?<!\d)\d+`. Now `pattern:(?<!\d)` ensures that a match does not start after another digit, just what we need.
18+
يمكننا القيام بذلك عن طريق تحديد مظهر سلبي آخر خلف: `pattern: (؟ <! -) (؟ <! \ d) \ d +`. الآن `النمط: (؟ <! \ d)` يضمن أن المطابقة لا تبدأ بعد رقم آخر ، فقط ما نحتاجه.
1919

20-
We can also join them into a single lookbehind here:
20+
يمكننا أيضًا أن ننضم إليهم في lookbehind خلفنا هنا:
2121

2222
```js run
2323
let regexp = /(?<![-\d])\d+/g;

9-regular-expressions/14-regexp-lookahead-lookbehind/1-find-non-negative-integers/task.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
# Find non-negative integers
1+
# البحث عن أعداد صحيحة غير سالبة
2+
هناك سلسلة من الأعداد الصحيحة.
3+
أنشئ تعبيرًا عاديًا لا يبحث إلا عن الكلمات غير السلبية (يُسمح بصفر).
24

3-
There's a string of integer numbers.
4-
5-
Create a regexp that looks for only non-negative ones (zero is allowed).
6-
7-
An example of use:
5+
مثال للاستخدام:
86
```js
97
let regexp = /your regexp/g;
108

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
In order to insert after the `<body>` tag, we must first find it. We can use the regular expression pattern `pattern:<body.*>` for that.
1+
للإدراج بعد علامة `<body>` ، يجب أن نجدها أولاً. يمكننا استخدام `نمط النقش العادي: <body. *>` لذلك.
22

3-
In this task we don't need to modify the `<body>` tag. We only need to add the text after it.
3+
في هذه المهمة ، لا نحتاج إلى تعديل علامة `<body>`. نحتاج فقط لإضافة النص بعده.
44

5-
Here's how we can do it:
5+
إليك كيفية القيام بذلك:
66

77
```js run
88
let str = '...<body style="...">...';
@@ -11,9 +11,9 @@ str = str.replace(/<body.*>/, '$&<h1>Hello</h1>');
1111
alert(str); // ...<body style="..."><h1>Hello</h1>...
1212
```
1313

14-
In the replacement string `$&` means the match itself, that is, the part of the source text that corresponds to `pattern:<body.*>`. It gets replaced by itself plus `<h1>Hello</h1>`.
14+
في السلسلة البديلة `$ &` تعني المطابقة نفسها ، أي جزء النص المصدر الذي يتوافق مع `pattern: <body. *>`. يتم استبداله بمفرده بالإضافة إلى `<h1> Hello </h1>`.
1515

16-
An alternative is to use lookbehind:
16+
البديل هو استخدام lookbehind:
1717

1818
```js run
1919
let str = '...<body style="...">...';
@@ -22,15 +22,15 @@ str = str.replace(/(?<=<body.*>)/, `<h1>Hello</h1>`);
2222
alert(str); // ...<body style="..."><h1>Hello</h1>...
2323
```
2424

25-
As you can see, there's only lookbehind part in this regexp.
25+
كما ترون ، هناك فقط جزء وراء النظر في هذا التعبير العادي.
2626

27-
It works like this:
28-
- At every position in the text.
29-
- Check if it's preceeded by `pattern:<body.*>`.
30-
- If it's so then we have the match.
27+
يعمل مثل هذا:
28+
- في كل موضع في النص.
29+
- تحقق مما إذا كان مسبوقًا بـ `النمط: <body. *>`.
30+
- إذا كان الأمر كذلك لدينا المباراة.
3131

32-
The tag `pattern:<body.*>` won't be returned. The result of this regexp is literally an empty string, but it matches only at positions preceeded by `pattern:<body.*>`.
32+
لن يتم إرجاع العلامة `pattern: <body. *>`. نتيجة هذا التعبير العادي هي حرفيا سلسلة فارغة ، لكنها تتطابق فقط في المواضع التي يسبقها `النمط: <body. *>`.
3333

34-
So we replaces the "empty line", preceeded by `pattern:<body.*>`, with `<h1>Hello</h1>`. That's the insertion after `<body>`.
34+
لذلك نستبدل "السطر الفارغ" ، مسبوقًا بـ "pattern: <body. *>` ، بـ `<h1> Hello </h1>`. هذا هو الإدراج بعد "<body>".
3535

36-
P.S. Regexp flags, such as `pattern:s` and `pattern:i` can also useful: `pattern:/<body.*>/si`. The `pattern:s` flag makes the dot `pattern:.` match a newline character, and `pattern:i` flag makes `pattern:<body>` also match `match:<BODY>` case-insensitively.
36+
ملاحظة. علامات Regexp ، مثل `pattern: s` و` pattern: i` يمكن أن تكون مفيدة أيضًا: `pattern: / <body. *> / si`. تجعل علامة `pattern: s` علامة` `pattern: .` تتطابق مع حرف سطر جديد ، وعلامة 'pattern: i` تجعل` `pattern: <body>` تتطابق أيضًا مع `match: <BODY>` غير حساس لحالة الأحرف.

9-regular-expressions/14-regexp-lookahead-lookbehind/2-insert-after-head/task.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
# Insert After Head
1+
# أدخل بعد المقدمة
22

3-
We have a string with an HTML Document.
3+
لدينا سلسلة مع مستند HTML.
44

5-
Write a regular expression that inserts `<h1>Hello</h1>` immediately after `<body>` tag. The tag may have attributes.
5+
اكتب تعبيرًا عاديًا يُدرج `<h1> مرحبًا </ h1>` مباشرة بعد علامة `<body>`. قد يكون للسمات سمات.
66

7-
For instance:
7+
على سبيل المثال:
88

99
```js
1010
let regexp = /your regular expression/;
@@ -20,7 +20,7 @@ let str = `
2020
str = str.replace(regexp, `<h1>Hello</h1>`);
2121
```
2222

23-
After that the value of `str` should be:
23+
بعد هذا من المفترض أن تصبح قيمة `str`:
2424
```html
2525
<html>
2626
<body style="height: 200px"><h1>Hello</h1>
Lines changed: 48 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,59 @@
1-
# Lookahead and lookbehind
1+
# Lookahead و lookbehind
22

3-
Sometimes we need to find only those matches for a pattern that are followed or preceeded by another pattern.
3+
في بعض الأحيان نحتاج إلى العثور فقط على تلك المطابقات لنمط يتبعه أو يسبقه نمط آخر.
44

5-
There's a special syntax for that, called "lookahead" and "lookbehind", together referred to as "lookaround".
5+
هناك صيغة خاصة لذلك ، تسمى "lookahead" و "lookbehind" ، يشار إليها معًا باسم "lookaround".
66

7-
For the start, let's find the price from the string like `subject:1 turkey costs 30€`. That is: a number, followed by `subject:` sign.
7+
في البداية ، دعنا نجد السعر من السلسلة مثل `الموضوع: 1 ديك رومي يكلف 30 يورو`. أي: رقم متبوعًا بعلامة `subject:`.
88

99
## Lookahead
1010

11-
The syntax is: `pattern:X(?=Y)`, it means "look for `pattern:X`, but match only if followed by `pattern:Y`". There may be any pattern instead of `pattern:X` and `pattern:Y`.
11+
الصيغة هي: `pattern: X (؟ = Y)` ، وتعني "ابحث عن` pattern: X` ، لكن تطابق فقط إذا تبعها "pattern: Y`". قد يكون هناك أي نمط بدلاً من `pattern:X` و `pattern:Y`.
1212

13-
For an integer number followed by `subject:€`, the regexp will be `pattern:\d+(?=€)`:
13+
بالنسبة لرقم صحيح متبوعًا بـ`subject:€`, سيكون regexp
14+
`pattern:\d+(?=€)`:
1415

1516
```js run
1617
let str = "1 turkey costs 30€";
1718

1819
alert( str.match(/\d+(?=€)/) ); // 30, the number 1 is ignored, as it's not followed by €
1920
```
2021

21-
Please note: the lookahead is merely a test, the contents of the parentheses `pattern:(?=...)` is not included in the result `match:30`.
22+
يرجى ملاحظة: lookahead هو مجرد اختبار ، ومحتويات "نمط قوسين: (؟ = ...)` غير مدرجة في النتيجة
23+
`match:30`.
2224

23-
When we look for `pattern:X(?=Y)`, the regular expression engine finds `pattern:X` and then checks if there's `pattern:Y` immediately after it. If it's not so, then the potential match is skipped, and the search continues.
25+
عندما نبحث عن "pattern: X (؟ = Y)` ، يعثر محرك التعبير العادي على "pattern: X" ثم يتحقق مما إذا كان هناك "pattern: Y" بعده مباشرة. إذا لم يكن الأمر كذلك ، يتم تخطي المطابقة المحتملة ، ويستمر البحث.
2426

25-
More complex tests are possible, e.g. `pattern:X(?=Y)(?=Z)` means:
27+
من الممكن إجراء اختبارات أكثر تعقيدًا ، على سبيل المثال `النمط: X (؟ = Y) (؟ = Z)` يعني:
2628

27-
1. Find `pattern:X`.
28-
2. Check if `pattern:Y` is immediately after `pattern:X` (skip if isn't).
29-
3. Check if `pattern:Z` is also immediately after `pattern:X` (skip if isn't).
30-
4. If both tests passed, then the `pattern:X` is a match, otherwise continue searching.
29+
1. ابحث عن `النمط: X`.
30+
2. تحقق مما إذا كان "النمط: Y" مباشرةً بعد "النمط: X" (يمكنك التخطي إذا لم يكن كذلك).
31+
3. تحقق مما إذا كان "النمط: Z" هو أيضًا مباشرةً بعد "النمط: X" (يمكنك التخطي إذا لم يكن كذلك).
32+
4. في حالة اجتياز كلا الاختبارين ، فإن "النمط: X" هو تطابق ، وإلا فتابع البحث.
3133

32-
In other words, such pattern means that we're looking for `pattern:X` followed by `pattern:Y` and `pattern:Z` at the same time.
34+
بمعنى آخر ، يعني هذا النمط أننا نبحث عن `pattern: X` متبوعًا بـ` pattern: Y` و `pattern: Z` في نفس الوقت.
3335

34-
That's only possible if patterns `pattern:Y` and `pattern:Z` aren't mutually exclusive.
36+
هذا ممكن فقط إذا كان النموذجان "pattern: Y" و "pattern: Z" لا يستبعد أحدهما الآخر.
37+
38+
على سبيل المثال ، `pattern: \ d + (؟ = \ s) (؟ =. * 30)` يبحث عن `pattern: \ d +` فقط إذا كان متبوعًا بمسافة ، ويوجد `30` في مكان ما بعده:
3539

36-
For example, `pattern:\d+(?=\s)(?=.*30)` looks for `pattern:\d+` only if it's followed by a space, and there's `30` somewhere after it:
3740

3841
```js run
3942
let str = "1 turkey costs 30€";
4043

4144
alert( str.match(/\d+(?=\s)(?=.*30)/) ); // 1
4245
```
4346

44-
In our string that exactly matches the number `1`.
47+
في سلسلتنا التي تتطابق تمامًا مع الرقم `1`.
4548

4649
## Negative lookahead
4750

48-
Let's say that we want a quantity instead, not a price from the same string. That's a number `pattern:\d+`, NOT followed by `subject:€`.
51+
لنفترض أننا نريد كمية بدلاً من ذلك ، وليس سعرًا من نفس السلسلة. هذا رقم `نمط: \ d +` ، وليس متبوعًا بـ `الموضوع: €`.
52+
53+
لذلك ، يمكن تطبيق lookahead سلبي.
4954

50-
For that, a negative lookahead can be applied.
55+
الصيغة هي: `pattern: X (؟! Y)` ، وتعني "search` pattern: X` ، ولكن فقط إذا لم يتبعها "pattern: Y`".
5156

52-
The syntax is: `pattern:X(?!Y)`, it means "search `pattern:X`, but only if not followed by `pattern:Y`".
5357

5458
```js run
5559
let str = "2 turkeys cost 60€";
@@ -59,15 +63,15 @@ alert( str.match(/\d+(?!€)/) ); // 2 (the price is skipped)
5963

6064
## Lookbehind
6165

62-
Lookahead allows to add a condition for "what follows".
66+
يسمح Lookahead بإضافة شرط لـ "ما يلي".
6367

64-
Lookbehind is similar, but it looks behind. That is, it allows to match a pattern only if there's something before it.
68+
Lookbehind مشابه ، لكنه يبدو في الخلف. أي أنه يسمح بمطابقة النمط فقط إذا كان هناك شيء قبله.
6569

66-
The syntax is:
67-
- Positive lookbehind: `pattern:(?<=Y)X`, matches `pattern:X`, but only if there's `pattern:Y` before it.
68-
- Negative lookbehind: `pattern:(?<!Y)X`, matches `pattern:X`, but only if there's no `pattern:Y` before it.
70+
الصيغة هي:
71+
- نظرة إيجابية خلف: `pattern: (؟ <= Y) X` ، تطابق` pattern: X` ، ولكن فقط في حالة وجود "pattern: Y` قبلها.
72+
- مظهر سلبي خلف: `pattern: (؟ <! Y) X` ، يطابق` pattern: X` ، ولكن فقط في حالة عدم وجود `pattern: Y` قبله.
6973

70-
For example, let's change the price to US dollars. The dollar sign is usually before the number, so to look for `$30` we'll use `pattern:(?<=\$)\d+` -- an amount preceded by `subject:$`:
74+
على سبيل المثال ، دعنا نغير السعر إلى الدولار الأمريكي. عادةً ما تكون علامة الدولار قبل الرقم ، لذلك للبحث عن `$ 30` ، سنستخدم` `النمط: (؟ <= \ $) \ d +` - مبلغ يسبقه `الموضوع: $`:
7175

7276
```js run
7377
let str = "1 turkey costs $30";
@@ -76,23 +80,23 @@ let str = "1 turkey costs $30";
7680
alert( str.match(/(?<=\$)\d+/) ); // 30 (skipped the sole number)
7781
```
7882

79-
And, if we need the quantity -- a number, not preceded by `subject:$`, then we can use a negative lookbehind `pattern:(?<!\$)\d+`:
83+
وإذا احتجنا إلى الكمية - رقمًا ، لا يسبقه "الموضوع: $` ، فيمكننا استخدام النمط السلبي خلف ": (؟ <! \ $) \ d +`:
8084

8185
```js run
8286
let str = "2 turkeys cost $60";
8387

8488
alert( str.match(/(?<!\$)\d+/) ); // 2 (skipped the price)
8589
```
8690

87-
## Capturing groups
91+
## التقاط المجموعات
8892

89-
Generally, the contents inside lookaround parentheses does not become a part of the result.
93+
بشكل عام ، لا تصبح المحتويات الموجودة داخل الأقواس حول جزء من النتيجة.
9094

91-
E.g. in the pattern `pattern:\d+(?=€)`, the `pattern:€` sign doesn't get captured as a part of the match. That's natural: we look for a number `pattern:\d+`, while `pattern:(?=€)` is just a test that it should be followed by `subject:`.
95+
على سبيل المثال في النموذج `pattern: \ d + (؟ = €)` ، لا يتم التقاط علامة `pattern: ` كجزء من المباراة. هذا طبيعي: نحن نبحث عن رقم `نقش: \ d +` ، بينما `نقش: (؟ = €)` هو مجرد اختبار يجب أن يتبعه `الموضوع: `.
9296

93-
But in some situations we might want to capture the lookaround expression as well, or a part of it. That's possible. Just wrap that part into additional parentheses.
97+
ولكن في بعض المواقف ، قد نرغب في التقاط تعبير lookaround أيضًا ، أو جزء منه. أن من الممكن. ما عليك سوى لف هذا الجزء بأقواس إضافية.
9498

95-
In the example below the currency sign `pattern:(€|kr)` is captured, along with the amount:
99+
في المثال أدناه ، تم تسجيل "نمط علامة العملة: (€ | kr)" ، بالإضافة إلى المبلغ:
96100

97101
```js run
98102
let str = "1 turkey costs 30€";
@@ -101,7 +105,7 @@ let regexp = /\d+(?=(€|kr))/; // extra parentheses around €|kr
101105
alert( str.match(regexp) ); // 30, €
102106
```
103107

104-
And here's the same for lookbehind:
108+
وإليك نفس الشيء بالنسبة إلى: lookbehind:
105109

106110
```js run
107111
let str = "1 turkey costs $30";
@@ -110,21 +114,21 @@ let regexp = /(?<=(\$|£))\d+/;
110114
alert( str.match(regexp) ); // 30, $
111115
```
112116

113-
## Summary
117+
## ملخص
114118

115-
Lookahead and lookbehind (commonly referred to as "lookaround") are useful when we'd like to match something depending on the context before/after it.
119+
Lookahead و lookbehind (يشار إليهما عادةً باسم "lookaround") مفيدان عندما نرغب في مطابقة شيء ما اعتمادًا على السياق قبله / بعده.
116120

117-
For simple regexps we can do the similar thing manually. That is: match everything, in any context, and then filter by context in the loop.
121+
بالنسبة إلى regexps البسيطة ، يمكننا القيام بنفس الشيء يدويًا. هذا هو: مطابقة كل شيء ، في أي سياق ، ثم التصفية حسب السياق في الحلقة.
118122

119-
Remember, `str.match` (without flag `pattern:g`) and `str.matchAll` (always) return matches as arrays with `index` property, so we know where exactly in the text it is, and can check the context.
123+
تذكر أن `str.match` (بدون العلامة` pattern: g`) و `str.matchAll` (دائمًا) ترجع التطابقات كمصفوفات مع خاصية` index` ، حتى نعرف مكانها بالضبط في النص ، ويمكننا التحقق من سياق الكلام.
120124

121-
But generally lookaround is more convenient.
125+
لكن بشكل عام يكون البحث أكثر ملاءمة.
122126

123-
Lookaround types:
127+
أنواع Lookaround:
124128

125-
| Pattern | type | matches |
129+
| النمط | النوع | التطابق |
126130
|--------------------|------------------|---------|
127-
| `X(?=Y)` | Positive lookahead | `pattern:X` if followed by `pattern:Y` |
128-
| `X(?!Y)` | Negative lookahead | `pattern:X` if not followed by `pattern:Y` |
129-
| `(?<=Y)X` | Positive lookbehind | `pattern:X` if after `pattern:Y` |
130-
| `(?<!Y)X` | Negative lookbehind | `pattern:X` if not after `pattern:Y` |
131+
| `X(?=Y)` | Positive lookahead | `pattern: X` إذا تبعه` pattern: Y` |
132+
| `X(?!Y)` | Negative lookahead | ``pattern: X` إذا لم يتبعه` pattern: Y` |
133+
| `(?<=Y)X` | Positive lookbehind | `pattern: X` إذا بعده` pattern: Y` |
134+
| `(?<!Y)X` | Negative lookbehind | `pattern:X` إذا لم يكن بعده `pattern:Y` |

0 commit comments

Comments
 (0)