HTML Diff
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>Если вы используете несколько групп, то не очень удобно запоминать их по номерам. Гораздо проще пользоваться именами. Для этого нужно добавить ?&lt;имя&gt; после открытия скобки:</p>
17 <p>Если вы используете несколько групп, то не очень удобно запоминать их по номерам. Гораздо проще пользоваться именами. Для этого нужно добавить ?&lt;имя&gt; после открытия скобки:</p>
18 <p>/(?&lt;group1&gt;ta|tu)-\k&lt;group1&gt;/</p>
18 <p>/(?&lt;group1&gt;ta|tu)-\k&lt;group1&gt;/</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&lt;group1&gt; означает обратную ссылку на группу с именем group1. Это означает, что после символа - должно быть то же самое значение, что и в группе group1.</p>
21 <p>Символ k используется для обратной ссылки на именованную группу. В данном случае, \k&lt;group1&gt; означает обратную ссылку на группу с именем 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>Для атомарной группировки вместо : используется символ &gt;:</p>
30 <p>Для атомарной группировки вместо : используется символ &gt;:</p>
31 <p>/a(?&gt;bc|b|x)cc/</p>
31 <p>/a(?&gt;bc|b|x)cc/</p>
32 <p>abcc axcc abcc</p>
32 <p>abcc axcc abcc</p>
33 <p>Когда мы добавляем символы атомарной группировки ?&gt;, происходит следующее:</p>
33 <p>Когда мы добавляем символы атомарной группировки ?&gt;, происходит следующее:</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>Давайте разберемся, как она работает. Если мы уберем символы ?&gt;, то регулярное выражение находит три подстроки - abcc, axcc и abcc:</p>
37 </ul><p>Давайте разберемся, как она работает. Если мы уберем символы ?&gt;, то регулярное выражение находит три подстроки - 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 -&gt; b -&gt; x, а после x - сопоставление cc.</p>
41 <p>При атомарной группировке возврат по строке до символа a отключается. Происходит дальнейшее движение по альтернативам bc -&gt; b -&gt; x, а после x - сопоставление cc.</p>
42 <p>Когда найдено первое совпадение из атомарной группы (?&gt;bc|b|x), другие варианты из этой группы не рассматриваются. Дальше идет поиск со следующего символа из анализируемой строки с первого символа регулярного выражения.</p>
42 <p>Когда найдено первое совпадение из атомарной группы (?&gt;bc|b|x), другие варианты из этой группы не рассматриваются. Дальше идет поиск со следующего символа из анализируемой строки с первого символа регулярного выражения.</p>
43 <p>Мы могли бы найти совпадение с подстрокой с атомарной группировкой, только если бы добавили к abcc еще один символ c:</p>
43 <p>Мы могли бы найти совпадение с подстрокой с атомарной группировкой, только если бы добавили к abcc еще один символ c:</p>
44 <p>/a(?&gt;bc|b|x)cc/</p>
44 <p>/a(?&gt;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>