0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>В этом уроке мы рассмотрим дополнительные возможности и различные виды группировки.</p>
1
<p>В этом уроке мы рассмотрим дополнительные возможности и различные виды группировки.</p>
2
<h3>Группировка с обратной связью</h3>
2
<h3>Группировка с обратной связью</h3>
3
<p>У нас есть группа символов, из которой мы выбираем либо ta, либо tu:</p>
3
<p>У нас есть группа символов, из которой мы выбираем либо ta, либо tu:</p>
4
<p>/(ta|tu)/</p>
4
<p>/(ta|tu)/</p>
5
<p>ta-tu ta-ta tu-tu</p>
5
<p>ta-tu ta-ta tu-tu</p>
6
<p>Предположим, что мы хотим найти только те подстроки, в которых левая и правая части совпадают: ta - ta и tu - tu. Попробуем дополнить наше выражение еще одним условием "или" и увидим, что реализовать задуманное не удалось:</p>
6
<p>Предположим, что мы хотим найти только те подстроки, в которых левая и правая части совпадают: ta - ta и tu - tu. Попробуем дополнить наше выражение еще одним условием "или" и увидим, что реализовать задуманное не удалось:</p>
7
<p>/(ta|tu)-(ta|tu)/</p>
7
<p>/(ta|tu)-(ta|tu)/</p>
8
<p>ta-tu ta-ta tu-tu</p>
8
<p>ta-tu ta-ta tu-tu</p>
9
<p>Здесь поможет<strong>группировка с обратной связью</strong>. Чтобы сделать ее, мы используем специальное обозначение \1. Оно указывает, что символы из первой группы нужно подставить вместо \1.</p>
9
<p>Здесь поможет<strong>группировка с обратной связью</strong>. Чтобы сделать ее, мы используем специальное обозначение \1. Оно указывает, что символы из первой группы нужно подставить вместо \1.</p>
10
<p>Таким образом, совпадают подстроки с одинаковыми левыми и правыми частями:</p>
10
<p>Таким образом, совпадают подстроки с одинаковыми левыми и правыми частями:</p>
11
<p>/(ta|tu)-\1/</p>
11
<p>/(ta|tu)-\1/</p>
12
<p>ta-tu ta-ta tu-tu</p>
12
<p>ta-tu ta-ta tu-tu</p>
13
<p>По умолчанию все созданные группы символов записываются в специальную область памяти и маркируются символами от \1 до \9. Если бы мы использовали квантификацию, то это не повлияло бы на результат. Дело в том, что квантификация не участвует в обратной связи - берется только первое вхождение в область памяти:</p>
13
<p>По умолчанию все созданные группы символов записываются в специальную область памяти и маркируются символами от \1 до \9. Если бы мы использовали квантификацию, то это не повлияло бы на результат. Дело в том, что квантификация не участвует в обратной связи - берется только первое вхождение в область памяти:</p>
14
<p>/(ta|tu)+-\1/</p>
14
<p>/(ta|tu)+-\1/</p>
15
<p>ta-tu ta-ta tu-tu</p>
15
<p>ta-tu ta-ta tu-tu</p>
16
<h3>Именованные группы</h3>
16
<h3>Именованные группы</h3>
17
<p>Если вы используете несколько групп, то не очень удобно запоминать их по номерам. Гораздо проще пользоваться именами. Для этого нужно добавить ?<имя> после открытия скобки:</p>
17
<p>Если вы используете несколько групп, то не очень удобно запоминать их по номерам. Гораздо проще пользоваться именами. Для этого нужно добавить ?<имя> после открытия скобки:</p>
18
<p>/(?<group1>ta|tu)-\k<group1>/</p>
18
<p>/(?<group1>ta|tu)-\k<group1>/</p>
19
<p>ta-tu ta-ta tu-tu</p>
19
<p>ta-tu ta-ta tu-tu</p>
20
<p>Теперь нам удобнее работать с группой в своем коде - можно ссылаться на группу по имени group1.</p>
20
<p>Теперь нам удобнее работать с группой в своем коде - можно ссылаться на группу по имени group1.</p>
21
<p>Символ k используется для обратной ссылки на именованную группу. В данном случае, \k<group1> означает обратную ссылку на группу с именем group1. Это означает, что после символа - должно быть то же самое значение, что и в группе group1.</p>
21
<p>Символ k используется для обратной ссылки на именованную группу. В данном случае, \k<group1> означает обратную ссылку на группу с именем group1. Это означает, что после символа - должно быть то же самое значение, что и в группе group1.</p>
22
<h3>Группировка без обратной связи</h3>
22
<h3>Группировка без обратной связи</h3>
23
<p>Мы можем отключить обратную связь, поставив ?: внутри нашей группы:</p>
23
<p>Мы можем отключить обратную связь, поставив ?: внутри нашей группы:</p>
24
<p>/(?:ta|tu)-\1/</p>
24
<p>/(?:ta|tu)-\1/</p>
25
<p>ta-tu ta-ta tu-tu</p>
25
<p>ta-tu ta-ta tu-tu</p>
26
<p>После этого группа перестанет сохраняться в специальную область памяти. При ее вызове возникнет ошибка, потому что такой группы в памяти не существует. При таком подходе регулярное выражение становится очень сложно читать, однако оно работает быстрее.</p>
26
<p>После этого группа перестанет сохраняться в специальную область памяти. При ее вызове возникнет ошибка, потому что такой группы в памяти не существует. При таком подходе регулярное выражение становится очень сложно читать, однако оно работает быстрее.</p>
27
<p>Это вполне рабочий метод. Он особенно подходит, если вы хотите, чтобы лишние группы не занимали много места и не мешали заниматься дальнейшей группировкой.</p>
27
<p>Это вполне рабочий метод. Он особенно подходит, если вы хотите, чтобы лишние группы не занимали много места и не мешали заниматься дальнейшей группировкой.</p>
28
<h3>Атомарная группировка</h3>
28
<h3>Атомарная группировка</h3>
29
<p>Еще одна интересная разновидность группировки без обратной связи -<strong>атомарная</strong>. Атомарная группировка не поддерживается некоторыми популярными языками программирования, в том числе JavaScript и Python. Тем не менее можно найти решения для их эмуляции на имеющихся конструкциях.</p>
29
<p>Еще одна интересная разновидность группировки без обратной связи -<strong>атомарная</strong>. Атомарная группировка не поддерживается некоторыми популярными языками программирования, в том числе JavaScript и Python. Тем не менее можно найти решения для их эмуляции на имеющихся конструкциях.</p>
30
<p>Для атомарной группировки вместо : используется символ >:</p>
30
<p>Для атомарной группировки вместо : используется символ >:</p>
31
<p>/a(?>bc|b|x)cc/</p>
31
<p>/a(?>bc|b|x)cc/</p>
32
<p>abcc axcc abcc</p>
32
<p>abcc axcc abcc</p>
33
<p>Когда мы добавляем символы атомарной группировки ?>, происходит следующее:</p>
33
<p>Когда мы добавляем символы атомарной группировки ?>, происходит следующее:</p>
34
<ul><li>Сначала находится символ a</li>
34
<ul><li>Сначала находится символ a</li>
35
<li>Затем - bc</li>
35
<li>Затем - bc</li>
36
<li>Затем - идет поиск cc</li>
36
<li>Затем - идет поиск cc</li>
37
</ul><p>Давайте разберемся, как она работает. Если мы уберем символы ?>, то регулярное выражение находит три подстроки - abcc, axcc и abcc:</p>
37
</ul><p>Давайте разберемся, как она работает. Если мы уберем символы ?>, то регулярное выражение находит три подстроки - abcc, axcc и abcc:</p>
38
<p>/a(bc|b|x)cc/</p>
38
<p>/a(bc|b|x)cc/</p>
39
<p>abcc axcc abcc</p>
39
<p>abcc axcc abcc</p>
40
<p>Рассмотрим подробнее этот пример. В обычном случае поиск откатился бы до a и продолжил бы проверку с b, потому что стоит символ альтернативы |. После этого мы бы дошли до cc - и проверка бы сработала.</p>
40
<p>Рассмотрим подробнее этот пример. В обычном случае поиск откатился бы до a и продолжил бы проверку с b, потому что стоит символ альтернативы |. После этого мы бы дошли до cc - и проверка бы сработала.</p>
41
<p>При атомарной группировке возврат по строке до символа a отключается. Происходит дальнейшее движение по альтернативам bc -> b -> x, а после x - сопоставление cc.</p>
41
<p>При атомарной группировке возврат по строке до символа a отключается. Происходит дальнейшее движение по альтернативам bc -> b -> x, а после x - сопоставление cc.</p>
42
<p>Когда найдено первое совпадение из атомарной группы (?>bc|b|x), другие варианты из этой группы не рассматриваются. Дальше идет поиск со следующего символа из анализируемой строки с первого символа регулярного выражения.</p>
42
<p>Когда найдено первое совпадение из атомарной группы (?>bc|b|x), другие варианты из этой группы не рассматриваются. Дальше идет поиск со следующего символа из анализируемой строки с первого символа регулярного выражения.</p>
43
<p>Мы могли бы найти совпадение с подстрокой с атомарной группировкой, только если бы добавили к abcc еще один символ c:</p>
43
<p>Мы могли бы найти совпадение с подстрокой с атомарной группировкой, только если бы добавили к abcc еще один символ c:</p>
44
<p>/a(?>bc|b|x)cc/</p>
44
<p>/a(?>bc|b|x)cc/</p>
45
<p>abccc axcc abcc</p>
45
<p>abccc axcc abcc</p>
46
<p>При такой группировке дальнейший поиск прекращается, после того как мы прошли все альтернативы из группы.</p>
46
<p>При такой группировке дальнейший поиск прекращается, после того как мы прошли все альтернативы из группы.</p>
47
<p>Подробный алгоритм можно описать так:</p>
47
<p>Подробный алгоритм можно описать так:</p>
48
<ol><li>Поиск начинается с первого символа анализируемой строки</li>
48
<ol><li>Поиск начинается с первого символа анализируемой строки</li>
49
<li>Если найдено совпадение до атомарной группы, то происходит поочередная подстановка вариантов</li>
49
<li>Если найдено совпадение до атомарной группы, то происходит поочередная подстановка вариантов</li>
50
<li>При первом найденном совпадении перебор вариантов завершается и продолжается поиск символов после атомарной группы</li>
50
<li>При первом найденном совпадении перебор вариантов завершается и продолжается поиск символов после атомарной группы</li>
51
<li>Если совпадение с регулярным выражением неполное, то поиск заканчивается. Это не зависит от того, были ли опробованы остальные варианты из группы</li>
51
<li>Если совпадение с регулярным выражением неполное, то поиск заканчивается. Это не зависит от того, были ли опробованы остальные варианты из группы</li>
52
<li>Дальнейший поиск по строке выполняется снова для всего регулярного выражения, но уже со следующего по порядку символа анализируемой строки</li>
52
<li>Дальнейший поиск по строке выполняется снова для всего регулярного выражения, но уже со следующего по порядку символа анализируемой строки</li>
53
</ol>
53
</ol>