Основы регулярных выражений
Регулярное выражение (regex) — это шаблон, описывающий текст. В этом руководстве рассматриваются основные элементы, которые используются чаще всего, и ловушки, из-за которых поиск становится медленным или даёт неожиданные совпадения.
Литералы и классы символов
Большинство символов совпадают сами с собой: шаблон cat находит текст «cat». Некоторые символы имеют особое значение, например . * + ? ( ) [ ] { } ^ $ | \. Чтобы найти такой символ буквально, экранируйте его обратной косой чертой, например \. для точки.
Класс символов совпадает с одним символом из набора. [abc] совпадает с a, b или c; [a-z] — со строчной латинской буквой ASCII; [^0-9] — с любым символом, кроме цифры. Распространённые сокращения: \d (цифра), \w (буква, цифра или подчёркивание), \s (пробельный символ) и их противоположности \D, \W и \S. Точка . совпадает с любым символом, кроме переноса строки.
В JavaScript \w и \d охватывают только символы ASCII. Чтобы находить буквы любого языка, используйте свойство Unicode, например \p{L}, с флагом u.
Квантификаторы и якоря
Квантификаторы указывают, сколько раз может повторяться предыдущий элемент:
| Синтаксис | Значение | Пример |
|---|---|---|
* |
0 или больше | ab* совпадает с a, ab, abbb |
+ |
1 или больше | \d+ совпадает с 7 или 2026 |
? |
0 или 1 | colou?r совпадает с color и colour |
{n,m} |
От n до m | \d{2,4} совпадает с 2–4 цифрами |
Якоря совпадают с позицией, а не с символом. ^ — начало, а $ — конец входного текста (или каждой строки с флагом m). \b — граница слова, поэтому \bcat\b находит «cat», но не «concatenate». При проверке значения целиком привязывайте оба конца: ^\d{5}$ принимает ровно пять цифр и ничего больше.
Группы и захват
Круглые скобки группируют часть шаблона, чтобы к ней применялся квантификатор или альтернатива: (ab)+ повторяет «ab», а (jpg|png) совпадает с любым из двух слов. Обычная группа также захватывает совпавший текст, который можно повторно использовать в замене как $1, $2 и так далее.
Именованные группы, например (?<year>\d{4}), делают шаблоны понятнее, и на них можно ссылаться как $<year>. Если нужна только группировка, незахватывающая группа (?:...) не создаёт лишнего захвата. Тестер RegEx от LeedyBox показывает каждое совпадение с его группами захвата и предпросмотр замен.
Флаги
Флаги меняют поведение всего шаблона. Распространённые флаги JavaScript:
g(global): находить все совпадения, а не только первое.i(ignore case): не различать заглавные и строчные буквы.m(multiline):^и$совпадают на каждом переносе строки.s(dotAll):.совпадает также с переносами строк.u(unicode): включает поиск с учётом Unicode и классы\p{...}.
В JavaScript есть также флаги y (sticky) и d (индексы совпадений), которые тестер тоже поддерживает.
Жадные и ленивые квантификаторы и катастрофические возвраты
По умолчанию квантификаторы жадные: они захватывают как можно больше, а затем отдают символы обратно, если остальная часть шаблона не совпадает. В тексте <b>bold</b> шаблон <.+> совпадает со всей строкой. Если добавить ?, квантификатор становится ленивым, и <.+?> совпадает только с <b>. Отрицательный класс вроде <[^>]+> часто понятнее и быстрее.
Большинство движков регулярных выражений, включая движок JavaScript, используют возвраты (backtracking). Вложенные квантификаторы вроде (a+)+$ или пересекающиеся альтернативы могут заставить движок перебирать огромное число комбинаций, когда совпадение не находится, и это может подвесить страницу или сервер. Это явление называется катастрофическими возвратами (catastrophic backtracking), и при недоверенном вводе его можно использовать для атак типа «отказ в обслуживании» (ReDoS). Не вкладывайте квантификаторы друг в друга над одними и теми же символами, предпочитайте конкретные классы вместо .* и тестируйте шаблоны на длинных несовпадающих строках.
Диалекты регулярных выражений различаются
Единого стандарта регулярных выражений нет. JavaScript, Python, Java, .NET, PCRE (используется в PHP), Go и базы данных поддерживают немного разный синтаксис. Ретроспективная проверка (lookbehind), сверхжадные (possessive) квантификаторы, синтаксис именованных групп, классы Unicode и синтаксис замен различаются. Например, движок RE2 в Go не поддерживает проверки окружения (lookaround) и обратные ссылки.
Тестер RegEx от LeedyBox использует движок JavaScript вашего браузера. Шаблон, который работает в нём, может потребовать изменений в другом языке, поэтому проверьте его ещё раз там, где он будет выполняться.
Часто задаваемые вопросы
Почему мой шаблон находит только первое вхождение?
Без флага g JavaScript останавливается после первого совпадения. Включите g, чтобы найти все совпадения.
Можно ли проверять адреса электронной почты регулярным выражением?
Регулярное выражение может проверить, что значение выглядит правдоподобно, но не может подтвердить, что адрес существует. Обычно для этого отправляют письмо с подтверждением.
Почему ^ совпадает только один раз в многострочном тексте?
По умолчанию ^ и $ относятся ко всему входному тексту. Включите флаг m, чтобы они совпадали в начале и конце каждой строки.