|
1 | | -# Обратные ссылки: \n и $n |
| 1 | +# Backreferences: \n and $n |
2 | 2 |
|
3 | | -Скобочные группы можно не только получать в результате. |
4 | | - |
5 | | -Движок регулярных выражений запоминает их содержимое, и затем его можно использовать как в самом паттерне, так и в строке замены. |
| 3 | +Capturing groups may be accessed not only in the result, but in the replacement string, and in the pattern too. |
6 | 4 |
|
7 | 5 | [cut] |
8 | 6 |
|
9 | | -## Группа в строке замены |
| 7 | +## Group in replacement: $n |
10 | 8 |
|
11 | | -Ссылки в строке замены имеют вид `$n`, где `n` -- это номер скобочной группы. |
| 9 | +When we are using `replace` method, we can access n-th group in the replacement string using `$n`. |
12 | 10 |
|
13 | | -Вместо `$n` подставляется содержимое соответствующей скобки: |
| 11 | +For instance: |
14 | 12 |
|
15 | 13 | ```js run |
16 | | -var name = "Александр Пушкин"; |
| 14 | +let name = "John Smith"; |
17 | 15 |
|
18 | | -name = name.replace(/([а-яё]+) ([а-яё]+)/i, *!*"$2, $1"*/!*); |
19 | | -alert( name ); // Пушкин, Александр |
| 16 | +name = name.replace(/(\w+) (\w+)/i, *!*"$2, $1"*/!*); |
| 17 | +alert( name ); // Smith, John |
20 | 18 | ``` |
21 | 19 |
|
22 | | -В примере выше вместо `pattern:$2` подставляется второе найденное слово, а вместо `pattern:$1` -- первое. |
| 20 | +Here `pattern:$1` in the replacement string means "substitute the content of the first group here", and `pattern:$2` means "substitute the second group here". |
23 | 21 |
|
24 | | -## Группа в шаблоне |
| 22 | +Referencing a group in the replacement string allows us to reuse the existing text during the replacement. |
25 | 23 |
|
26 | | -Выше был пример использования содержимого групп в строке замены. Это удобно, когда нужно реорганизовать содержимое или создать новое с использованием старого. |
| 24 | +## Group in pattern: \n |
27 | 25 |
|
28 | | -Но к скобочной группе можно также обратиться в самом поисковом шаблоне, ссылкой вида `\номер`. |
| 26 | +A group can be referenced in the pattern using `\n`. |
29 | 27 |
|
30 | | -Чтобы было яснее, рассмотрим это на реальной задаче -- необходимо найти в тексте строку в кавычках. Причём кавычки могут быть одинарными `subject:'...'` или двойными `subject:"..."` -- и то и другое должно искаться корректно. |
| 28 | +To make things clear let's consider a task. We need to find a quoted string: either a single-quoted `subject:'...'` or a double-quoted `subject:"..."` -- both variants need to match. |
31 | 29 |
|
32 | | -Как такие строки искать? |
| 30 | +How to look for them? |
33 | 31 |
|
34 | | -Можно в регэкспе предусмотреть произвольные кавычки: `pattern:['"](.*?)['"]`. Такой регэксп найдёт строки вида `match:"..."`, `match:'...'`, но он даст неверный ответ в случае, если одна кавычка ненароком оказалась внутри другой, как например в строке `subject:"She's the one!"`: |
| 32 | +We can put two kinds of quotes in the pattern: `pattern:['"](.*?)['"]`. That finds strings like `match:"..."` and `match:'...'`, but it gives incorrect matches when one quote appears inside another one, like the string `subject:"She's the one!"`: |
35 | 33 |
|
36 | 34 | ```js run |
37 | | -var str = "He said: \"She's the one!\"."; |
| 35 | +let str = "He said: \"She's the one!\"."; |
38 | 36 |
|
39 | | -var reg = /['"](.*?)['"]/g; |
| 37 | +let reg = /['"](.*?)['"]/g; |
40 | 38 |
|
41 | | -// Результат не соответствует замыслу |
| 39 | +// The result is not what we expect |
42 | 40 | alert( str.match(reg) ); // "She' |
43 | 41 | ``` |
44 | 42 |
|
45 | | -Как видно, регэксп нашёл открывающую кавычку `match:"`, затем текст, вплоть до новой кавычки `match:'`, которая закрывает соответствие. |
| 43 | +As we can see, the pattern found an opening quote `match:"`, then the text is consumed lazily till the other quote `match:'`, that closes the match. |
46 | 44 |
|
47 | | -Для того, чтобы попросить регэксп искать закрывающую кавычку -- такую же, как открывающую, мы обернём её в скобочную группу и используем обратную ссылку на неё: |
| 45 | +To make sure that the pattern looks for the closing quote exactly the same as the opening one, let's make a group of it and use the backreference: |
48 | 46 |
|
49 | 47 | ```js run |
50 | | -var str = "He said: \"She's the one!\"."; |
| 48 | +let str = "He said: \"She's the one!\"."; |
51 | 49 |
|
52 | | -var reg = /(['"])(.*?)\1/g; |
| 50 | +let reg = /(['"])(.*?)\1/g; |
53 | 51 |
|
54 | 52 | alert( str.match(reg) ); // "She's the one!" |
55 | 53 | ``` |
56 | 54 |
|
57 | | -Теперь работает верно! Движок регулярных выражений, найдя первое скобочное выражение -- кавычку `pattern:(['"])`, запоминает его и далее `pattern:\1` означает "найти то же самое, что в первой скобочной группе". |
| 55 | +Now everything's correct! The regular expression engine finds the first quote `pattern:(['"])` and remembers the content of `pattern:(...)`, that's the first capturing group. |
58 | 56 |
|
59 | | -Обратим внимание на два нюанса: |
| 57 | +Further in the pattern `pattern:\1` means "find the same text as in the first group". |
60 | 58 |
|
61 | | -- Чтобы использовать скобочную группу в строке замены -- нужно использовать ссылку вида `$1`, а в шаблоне -- обратный слэш: `\1`. |
62 | | -- Чтобы в принципе иметь возможность обратиться к скобочной группе -- не важно откуда, она не должна быть исключена из запоминаемых при помощи `?:`. Скобочные группы вида `(?:...)` не участвуют в нумерации. |
| 59 | +Please note: |
63 | 60 |
|
| 61 | +- To reference a group inside a replacement string -- we use `$1`, while in the pattern -- a backslash `\1`. |
| 62 | +- If we use `?:` in the group, then we can't reference it. Groups that are excluded from capturing `(?:...)` are not remembered by the engine. |
0 commit comments