HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Если вы когда-либо работали с командной строкой, вы, вероятнее всего, использовали маски имён файлов. Допустим, если хотели полностью удалить файлы в текущей директории, начинающиеся на букву "d", писали команду rm d*.</p>
1 <p>Если вы когда-либо работали с командной строкой, вы, вероятнее всего, использовали маски имён файлов. Допустим, если хотели полностью удалить файлы в текущей директории, начинающиеся на букву "d", писали команду rm d*.</p>
2 <p>В принципе,<strong>регулярные выражения</strong>- это схожий инструмент, однако более мощный. Он позволяет искать строки, проверять их на соответствие определённому шаблону и т. п. Англоязычное название -<strong>Regular Expressions</strong>либо просто<strong>RegExp</strong>. Можно сказать, что регулярные выражения - это язык, описывающий шаблоны строк.</p>
2 <p>В принципе,<strong>регулярные выражения</strong>- это схожий инструмент, однако более мощный. Он позволяет искать строки, проверять их на соответствие определённому шаблону и т. п. Англоязычное название -<strong>Regular Expressions</strong>либо просто<strong>RegExp</strong>. Можно сказать, что регулярные выражения - это язык, описывающий шаблоны строк.</p>
3 <p>Реализация данного инструмента на разных языках программирования различается, правда, не очень сильно. В этой статье мы поговорим о регулярных выражениях в контексте их реализации на Perl.</p>
3 <p>Реализация данного инструмента на разных языках программирования различается, правда, не очень сильно. В этой статье мы поговорим о регулярных выражениях в контексте их реализации на Perl.</p>
4 <h2>Основы синтаксиса</h2>
4 <h2>Основы синтаксиса</h2>
5 <p>Для начала отметим, что любая строка уже сама по себе -<strong>это регулярное выражение</strong>. Например, выражению Хаха будет соответствовать строка "Хаха" и лишь она. При этом стоит учитывать, что регулярные выражения регистрозависимы, а значит, "хаха" уже будет совсем другим выражением.</p>
5 <p>Для начала отметим, что любая строка уже сама по себе -<strong>это регулярное выражение</strong>. Например, выражению Хаха будет соответствовать строка "Хаха" и лишь она. При этом стоит учитывать, что регулярные выражения регистрозависимы, а значит, "хаха" уже будет совсем другим выражением.</p>
6 <p>Регулярные выражения имеют<strong>спецсимволы</strong>, их нужно экранировать. Список выглядит следующим образом:</p>
6 <p>Регулярные выражения имеют<strong>спецсимволы</strong>, их нужно экранировать. Список выглядит следующим образом:</p>
7 . ^ $ * + ? { } [ ] \ | ( )<p>Для экранирования используют \, добавляя его перед спецсимволом.</p>
7 . ^ $ * + ? { } [ ] \ | ( )<p>Для экранирования используют \, добавляя его перед спецсимволом.</p>
8 <h2>Набор символов</h2>
8 <h2>Набор символов</h2>
9 <p>Допустим, надо найти в тексте все междометия, которые обозначают смех. Мы не можем написать просто Хаха, так как не будут учтены такие междометия, как "Хихи", "Хохо", "Хехе" и т. д. И вот здесь нам и пригодятся наборы, которые записываются в квадратных скобках. Вместо того, чтобы указывать конкретный символ, мы можем записать список, то есть строка будет считаться подходящей, если в ней будет находиться любой символ из перечисленных в списке.</p>
9 <p>Допустим, надо найти в тексте все междометия, которые обозначают смех. Мы не можем написать просто Хаха, так как не будут учтены такие междометия, как "Хихи", "Хохо", "Хехе" и т. д. И вот здесь нам и пригодятся наборы, которые записываются в квадратных скобках. Вместо того, чтобы указывать конкретный символ, мы можем записать список, то есть строка будет считаться подходящей, если в ней будет находиться любой символ из перечисленных в списке.</p>
10 <p>К примеру, паттерну [abcd] соответствует любой из символов d, c, b или a.</p>
10 <p>К примеру, паттерну [abcd] соответствует любой из символов d, c, b или a.</p>
11 <p>Большинство спецсимволов внутри набора не нуждается в экранировании, но применение перед ними "\" не будет ошибкой. Нужно экранировать символы "^" и "\", рекомендуется экранировать "]" и "-". Последний применяется для задания диапазонов, но об этом ниже.</p>
11 <p>Большинство спецсимволов внутри набора не нуждается в экранировании, но применение перед ними "\" не будет ошибкой. Нужно экранировать символы "^" и "\", рекомендуется экранировать "]" и "-". Последний применяется для задания диапазонов, но об этом ниже.</p>
12 <p>Если мы после "[" запишем символ "^",<strong>набор получит обратный смысл</strong>, а подходящим станет считаться любой символ, кроме тех, что указаны. К примеру, паттерну [^xyz] будет соответствовать любой символ, кроме "x", "y" и "z".</p>
12 <p>Если мы после "[" запишем символ "^",<strong>набор получит обратный смысл</strong>, а подходящим станет считаться любой символ, кроме тех, что указаны. К примеру, паттерну [^xyz] будет соответствовать любой символ, кроме "x", "y" и "z".</p>
13 <p>Если вернуться к нашему случаю, то после написания [Хх][аоие]х[аоие] любая из строк "Хаха", "хихи", "хехе" и даже "Хохо" будет отвечать шаблону.</p>
13 <p>Если вернуться к нашему случаю, то после написания [Хх][аоие]х[аоие] любая из строк "Хаха", "хихи", "хехе" и даже "Хохо" будет отвечать шаблону.</p>
14 <h2>Предопределённые классы символов</h2>
14 <h2>Предопределённые классы символов</h2>
15 <p>Для ряда часто используемых наборов есть специальные шаблоны. Так, для пробела, табуляции и переноса строки применяют \s, для цифр - \d, для подчёркивания, символов латиницы - \w. Когда нужно описать любой символ вообще, применяют точку - ..</p>
15 <p>Для ряда часто используемых наборов есть специальные шаблоны. Так, для пробела, табуляции и переноса строки применяют \s, для цифр - \d, для подчёркивания, символов латиницы - \w. Когда нужно описать любой символ вообще, применяют точку - ..</p>
16 <p>Если вы указанные выше классы напишете с прописной буквы (\S, \D, \W), они поменяют смысл на противоположный.</p>
16 <p>Если вы указанные выше классы напишете с прописной буквы (\S, \D, \W), они поменяют смысл на противоположный.</p>
17 <p>Кроме всего прочего, с помощью регулярных выражений можно проверить, где находится строка по сравнению с остальным текстом. Допустим, выражение \b служит для обозначения границы слова, \B - не границы слова, ^- началa текста,$ - конца текста.</p>
17 <p>Кроме всего прочего, с помощью регулярных выражений можно проверить, где находится строка по сравнению с остальным текстом. Допустим, выражение \b служит для обозначения границы слова, \B - не границы слова, ^- началa текста,$ - конца текста.</p>
18 <p>Таким образом, паттерн \bJava\b в строке "Java and JavaScript" найдёт первые 4 символа, а паттерн \bJava\B обнаружит символы c 10-го по 13-й.</p>
18 <p>Таким образом, паттерн \bJava\b в строке "Java and JavaScript" найдёт первые 4 символа, а паттерн \bJava\B обнаружит символы c 10-го по 13-й.</p>
19 <h2>Диапазоны</h2>
19 <h2>Диапазоны</h2>
20 <p>Иногда возникает необходимость обозначить определённый набор, включающий в себя буквы, к примеру, от "б" до "ф". Чтобы не писать [бвгдежзиклмнопрстуф], вы можете задействовать механизм диапазонов, то есть написать лишь [б-ф].</p>
20 <p>Иногда возникает необходимость обозначить определённый набор, включающий в себя буквы, к примеру, от "б" до "ф". Чтобы не писать [бвгдежзиклмнопрстуф], вы можете задействовать механизм диапазонов, то есть написать лишь [б-ф].</p>
21 <p>Механизм особенно полезен для русского языка в силу отсутствия конструкции, аналогичной \w. Если хотите обозначить все буквы из русского алфавита, подойдёт паттерн [а-яА-ЯёЁ]. Учтите, что "ё" не включена в общий диапазон букв, поэтому её следует указывать отдельно.</p>
21 <p>Механизм особенно полезен для русского языка в силу отсутствия конструкции, аналогичной \w. Если хотите обозначить все буквы из русского алфавита, подойдёт паттерн [а-яА-ЯёЁ]. Учтите, что "ё" не включена в общий диапазон букв, поэтому её следует указывать отдельно.</p>
22 <h2>Квантификаторы в регулярных выражениях (указатели количества повторений)</h2>
22 <h2>Квантификаторы в регулярных выражениях (указатели количества повторений)</h2>
23 <p>Что делать, когда в нашем "смеющемся" междометии окажется между буквами "х" более, чем одна гласная ("Хаахааа")? Подготовленное нами ранее регулярное выражение уже помочь не сможет. А значит, не обойтись без использования<strong>квантификаторов</strong>.</p>
23 <p>Что делать, когда в нашем "смеющемся" междометии окажется между буквами "х" более, чем одна гласная ("Хаахааа")? Подготовленное нами ранее регулярное выражение уже помочь не сможет. А значит, не обойтись без использования<strong>квантификаторов</strong>.</p>
24 <p>Здесь следует отметить, что квантификатор применяется только к тому символу, который расположен перед ним. Часто используемые конструкции имеют в языке регулярных выражений особые обозначения:</p>
24 <p>Здесь следует отметить, что квантификатор применяется только к тому символу, который расположен перед ним. Часто используемые конструкции имеют в языке регулярных выражений особые обозначения:</p>
25 <p>Итак, благодаря квантификаторам, можно улучшить шаблон для тех же междометий, написав [Хх][аоеи]+х[аоеи]*. Теперь он распознает строки типа "Хааха", "Хихии", "хееех".</p>
25 <p>Итак, благодаря квантификаторам, можно улучшить шаблон для тех же междометий, написав [Хх][аоеи]+х[аоеи]*. Теперь он распознает строки типа "Хааха", "Хихии", "хееех".</p>
26 <h2>"Ленивая" квантификация и регулярные выражения</h2>
26 <h2>"Ленивая" квантификация и регулярные выражения</h2>
27 <p>Представим, что у нас есть задача по поиску всех<strong>HTML</strong>-тегов в строке:</p>
27 <p>Представим, что у нас есть задача по поиску всех<strong>HTML</strong>-тегов в строке:</p>
28 &lt;p&gt;&lt;b&gt;Otus&lt;/b&gt; - моя &lt;i&gt;любимая&lt;/i&gt; школа онлайн-образования!&lt;/p&gt;<p>Очевидно, что простое решение &lt;.*&gt; тут работать не будет, так как найдётся вся строка полностью, ведь она начинается и заканчивается тегом абзаца. Можно сказать, что содержимым тега считается следующая строка:</p>
28 &lt;p&gt;&lt;b&gt;Otus&lt;/b&gt; - моя &lt;i&gt;любимая&lt;/i&gt; школа онлайн-образования!&lt;/p&gt;<p>Очевидно, что простое решение &lt;.*&gt; тут работать не будет, так как найдётся вся строка полностью, ведь она начинается и заканчивается тегом абзаца. Можно сказать, что содержимым тега считается следующая строка:</p>
29 p&gt;&lt;b&gt;Otus&lt;/b&gt; - моя &lt;i&gt;любимая&lt;/i&gt; школа онлайн-образования!&lt;/p<p>Так происходит потому, что по умолчанию квантификатор в регулярных выражениях функционирует по, если можно так выразиться, "жадному алгоритму", то есть пытается вернуть самую длинную строку, которая отвечает условию. Проблема решается двумя способами: 1. Используется выражение &lt;[^&gt;]*&gt;. Оно запрещает правую угловую скобку считать содержимым тега. 2. Квантификатор объявляется "ленивым", а не "жадным". Для этого справа к квантификатору добавляется символ ?. Таким образом, при поиске всех тегов выражение обратится в &lt;.*?&gt;.</p>
29 p&gt;&lt;b&gt;Otus&lt;/b&gt; - моя &lt;i&gt;любимая&lt;/i&gt; школа онлайн-образования!&lt;/p<p>Так происходит потому, что по умолчанию квантификатор в регулярных выражениях функционирует по, если можно так выразиться, "жадному алгоритму", то есть пытается вернуть самую длинную строку, которая отвечает условию. Проблема решается двумя способами: 1. Используется выражение &lt;[^&gt;]*&gt;. Оно запрещает правую угловую скобку считать содержимым тега. 2. Квантификатор объявляется "ленивым", а не "жадным". Для этого справа к квантификатору добавляется символ ?. Таким образом, при поиске всех тегов выражение обратится в &lt;.*?&gt;.</p>
30 <h2>"Ревнивая" квантификация и регулярные выражения</h2>
30 <h2>"Ревнивая" квантификация и регулярные выражения</h2>
31 <p>Порой, для повышения скорости поиска (например, если строка не соответствует регулярному выражению) алгоритму запрещают возвращаться к предыдущим шагам поиска в целях нахождения возможных соответствий для оставшейся части регулярного выражения. Это "ревнивая" квантификация. Квантификатор становится таковым при добавлении к нему справа символа +. Другое применение - исключение нежелательных совпадений. Таким образом, паттерну ab*+a в строке "ababa" соответствуют лишь первые 3 символа, но не соответствуют символы с 3-го по 5-й, ведь символ "a", находящийся на 3-й позиции, уже использовался для получения первого результата.</p>
31 <p>Порой, для повышения скорости поиска (например, если строка не соответствует регулярному выражению) алгоритму запрещают возвращаться к предыдущим шагам поиска в целях нахождения возможных соответствий для оставшейся части регулярного выражения. Это "ревнивая" квантификация. Квантификатор становится таковым при добавлении к нему справа символа +. Другое применение - исключение нежелательных совпадений. Таким образом, паттерну ab*+a в строке "ababa" соответствуют лишь первые 3 символа, но не соответствуют символы с 3-го по 5-й, ведь символ "a", находящийся на 3-й позиции, уже использовался для получения первого результата.</p>
32 <h2>Скобочные группы</h2>
32 <h2>Скобочные группы</h2>
33 <p>Для шаблона "смеющегося" междометия осталось всего ничего - учесть то обстоятельство, что буква "х" способна встречаться больше, чем один раз, допустим, "Хахахахааахахооо", да и вообще, слово может не заканчиваться на "х". Можно задействовать квантификатор для группы [аиое]+х, однако если мы просто укажем [аиое]х+, квантификатор + будет относиться лишь к символу "х", но не к выражению целиком. Дабы это исправить, регулярное выражение следует взять в круглые скобки: ([аиое]х)+.</p>
33 <p>Для шаблона "смеющегося" междометия осталось всего ничего - учесть то обстоятельство, что буква "х" способна встречаться больше, чем один раз, допустим, "Хахахахааахахооо", да и вообще, слово может не заканчиваться на "х". Можно задействовать квантификатор для группы [аиое]+х, однако если мы просто укажем [аиое]х+, квантификатор + будет относиться лишь к символу "х", но не к выражению целиком. Дабы это исправить, регулярное выражение следует взять в круглые скобки: ([аиое]х)+.</p>
34 <p>Итак, регулярное выражение преобразуется в [Хх]([аиое]х?)+, причём в начале следует строчная либо заглавная "х", потом - ненулевое произвольное количество гласных, которые перемежаются одиночными строчными "х" (возможно, однако необязательно). Но это регулярное выражение решает проблему лишь частично, ведь под него попадут и такие строки, как, допустим, "хихахех". Но можно использовать набор изо всех гласных только единожды, а потом опираться на результаты первого поиска. Но как это сделать?</p>
34 <p>Итак, регулярное выражение преобразуется в [Хх]([аиое]х?)+, причём в начале следует строчная либо заглавная "х", потом - ненулевое произвольное количество гласных, которые перемежаются одиночными строчными "х" (возможно, однако необязательно). Но это регулярное выражение решает проблему лишь частично, ведь под него попадут и такие строки, как, допустим, "хихахех". Но можно использовать набор изо всех гласных только единожды, а потом опираться на результаты первого поиска. Но как это сделать?</p>
35 <h2>Обратная связь - запоминание результата поиска по группе</h2>
35 <h2>Обратная связь - запоминание результата поиска по группе</h2>
36 <p>Результат поиска по скобочной группе сохраняется в отдельной ячейке памяти, а доступ к ней разрешён для применения в последующих частях регулярного выражения. Если вернуться к задаче поиска<strong>HTML</strong>-тегов на странице, давайте представим, что нужно не только найти теги, но и определить их названия. В данном случае поможет регулярное выражение &lt;(.*?)&gt;.</p>
36 <p>Результат поиска по скобочной группе сохраняется в отдельной ячейке памяти, а доступ к ней разрешён для применения в последующих частях регулярного выражения. Если вернуться к задаче поиска<strong>HTML</strong>-тегов на странице, давайте представим, что нужно не только найти теги, но и определить их названия. В данном случае поможет регулярное выражение &lt;(.*?)&gt;.</p>
37 &lt;p&gt;&lt;b&gt;Otus&lt;/b&gt; - моя &lt;i&gt;любимая&lt;/i&gt; школа онлайн-образования!&lt;/p&gt;<p>Вот результат поиска по всему регулярному выражению:</p>
37 &lt;p&gt;&lt;b&gt;Otus&lt;/b&gt; - моя &lt;i&gt;любимая&lt;/i&gt; школа онлайн-образования!&lt;/p&gt;<p>Вот результат поиска по всему регулярному выражению:</p>
38 "&lt;p&gt;", "&lt;b&gt;", "&lt;/b&gt;", "&lt;i&gt;", "&lt;/i&gt;", "&lt;/p&gt;".<p>А вот итог поиска по 1-й группе:</p>
38 "&lt;p&gt;", "&lt;b&gt;", "&lt;/b&gt;", "&lt;i&gt;", "&lt;/i&gt;", "&lt;/p&gt;".<p>А вот итог поиска по 1-й группе:</p>
39 "p", "b", "/b", "i", "/i", "/i", "/p".<p>Вы можете ссылаться на результат поиска по группе с помощью регулярного выражения \n, в котором n - это цифра в пределах 1-9. К примеру, регулярному выражению (\w)(\w)\1\2 отвечают строки "aaaa", "abab", однако они не соответствует "aabb".</p>
39 "p", "b", "/b", "i", "/i", "/i", "/p".<p>Вы можете ссылаться на результат поиска по группе с помощью регулярного выражения \n, в котором n - это цифра в пределах 1-9. К примеру, регулярному выражению (\w)(\w)\1\2 отвечают строки "aaaa", "abab", однако они не соответствует "aabb".</p>
40 <p>Когда выражение берётся в скобки лишь для использования в её отношении квантификатора, то сразу после первой скобки следует добавить ?:, допустим, (?:[abcd]+\w).</p>
40 <p>Когда выражение берётся в скобки лишь для использования в её отношении квантификатора, то сразу после первой скобки следует добавить ?:, допустим, (?:[abcd]+\w).</p>
41 <p>С применением данного механизма мы легко перепишем всё регулярное выражение, приведя его к следующему виду:</p>
41 <p>С применением данного механизма мы легко перепишем всё регулярное выражение, приведя его к следующему виду:</p>
42 <h2>Перечисление</h2>
42 <h2>Перечисление</h2>
43 <p>Желаете проверить, соответствует ли строка хотя бы одному из шаблонов? Воспользуйтесь аналогом булевого оператора<strong>OR</strong>, записываемого посредством символа |. Здесь, под шаблон Лена|Одиночество попадают строки и "Лена", и "Одиночество".</p>
43 <p>Желаете проверить, соответствует ли строка хотя бы одному из шаблонов? Воспользуйтесь аналогом булевого оператора<strong>OR</strong>, записываемого посредством символа |. Здесь, под шаблон Лена|Одиночество попадают строки и "Лена", и "Одиночество".</p>
44 <p>Удобно применять перечисления внутри скобочных групп. Так, регулярное выражение (?:a|b|c|d) абсолютно эквивалентно [abcd]. В этом случае 2-й вариант даже лучше из-за читаемости и производительности.</p>
44 <p>Удобно применять перечисления внутри скобочных групп. Так, регулярное выражение (?:a|b|c|d) абсолютно эквивалентно [abcd]. В этом случае 2-й вариант даже лучше из-за читаемости и производительности.</p>
45 <p>Используя данный оператор, мы легко добавим к регулярному выражению для поиска междометий способность распознавать смех типа "Ахахаах" - это единственная усмешка, начинающаяся с гласной:</p>
45 <p>Используя данный оператор, мы легко добавим к регулярному выражению для поиска междометий способность распознавать смех типа "Ахахаах" - это единственная усмешка, начинающаяся с гласной:</p>
46 [Хх]([аоие])х?(?:\1х?)*|[Аа]х?(?:ах?)+<h2>Полезные сервисы по регулярным выражениям</h2>
46 [Хх]([аоие])х?(?:\1х?)*|[Аа]х?(?:ах?)+<h2>Полезные сервисы по регулярным выражениям</h2>
47 <p>Проверить своё регулярное выражение и потренироваться можно на специальных сервисах:<a>RegExr</a>,<a>Regex101</a>,<a>Regexpal</a>.</p>
47 <p>Проверить своё регулярное выражение и потренироваться можно на специальных сервисах:<a>RegExr</a>,<a>Regex101</a>,<a>Regexpal</a>.</p>
48 <p>Если хотите понять, как работает регулярное выражение, попавшее к вам в руки, используйте<a>Regexper</a>- это сервис, который способен строить понятные диаграммы на основе регулярных выражений.</p>
48 <p>Если хотите понять, как работает регулярное выражение, попавшее к вам в руки, используйте<a>Regexper</a>- это сервис, который способен строить понятные диаграммы на основе регулярных выражений.</p>
49 <p>Также существует визуальный конструктор функций JS, предназначенный для работы с регулярными выражениями - это<a>RegExp Builder</a>.</p>
49 <p>Также существует визуальный конструктор функций JS, предназначенный для работы с регулярными выражениями - это<a>RegExp Builder</a>.</p>
50 <p>Помните: не всегда следует решать задачу с помощью регулярных выражений (вспоминаем известный анекдот про программиста и проблему, которая превратилась в две проблемы). В некоторых случаях, к примеру, лучше написать развёрнутый автомат конечных состояний.</p>
50 <p>Помните: не всегда следует решать задачу с помощью регулярных выражений (вспоминаем известный анекдот про программиста и проблему, которая превратилась в две проблемы). В некоторых случаях, к примеру, лучше написать развёрнутый автомат конечных состояний.</p>
51  
51