Регулярные выражения: полное руководство для разработчиков
Практическое руководство по регулярным выражениям: базовый синтаксис, группы захвата, lookahead/lookbehind, типичные паттерны и отладка в разных языках программирования.
Регулярные выражения — это инструмент, который разработчики либо любят, либо избегают полностью. Они выглядят устрашающе — плотная строка специальных символов, кажущаяся непостижимой, — но базовая модель проста. Как только вы понимаете, как они работают, хорошо написанное регулярное выражение превращается в один из мощнейших однострочных инструментов во всём вашем арсенале.
Это руководство отсекает лишнее. Вместо перечисления всех возможностей регулярных выражений оно сосредоточено на 20% синтаксиса, покрывающего 80% реальных задач: классы символов, квантификаторы, якоря, группы и флаги. По ходу дела вы можете тестировать каждый пример в Тестере регулярных выражений BrowseryTools — бесплатно, без регистрации, всё остаётся в браузере.
Что такое регулярное выражение?
Регулярное выражение — это паттерн, описывающий множество строк. Применяя регулярное выражение к тексту, вы спрашиваете: «соответствует ли эта строка моему паттерну?» — или, на практике: «найди все подстроки, соответствующие моему паттерну». Сам паттерн записывается на компактном мини-языке, нативно поддерживаемом большинством языков программирования.
Регулярные выражения полезны всякий раз, когда нужно валидировать ввод (является ли это корректным email-адресом?), извлечь данные (выбрать все URL из блока текста), преобразовать текст (заменить все вхождения паттерна) или разбить строку по сложному разделителю. Они работают в браузере, на сервере, в терминале — везде.
Основной синтаксис: 20%, покрывающие 80% задач
Литеральные символы и точка
Большинство символов в регулярном выражении совпадают сами с собой. Паттерн hello буквально совпадает со строкой «hello». Точка . — единственный универсальный подстановочный символ, совпадающий с любым одним символом, кроме новой строки. Так, h.llo совпадает с «hello», «hallo», «hxllo» и так далее.
Классы символов
Квадратные скобки определяют класс символов — набор, из которого в данной позиции может совпасть любой один символ.
[aeiou]— совпадает с любой гласной[a-z]— совпадает с любой строчной буквой (синтаксис диапазона)[A-Za-z0-9]— совпадает с любым буквенно-цифровым символом[^0-9]—^внутри скобок инвертирует класс; совпадает с чем угодно, кроме цифры
Сокращённые классы охватывают наиболее распространённые случаи: \d — любая цифра (то же, что [0-9]), \w — любой «словесный» символ (буквы, цифры, подчёркивание), \s — любой пробельный символ. Их заглавные обратные — \D, \W, \S — совпадают с противоположным.
Квантификаторы
Квантификаторы управляют количеством повторений предшествующего элемента.
*— ноль или более раз+— один или более раз?— ноль или один раз (делает элемент необязательным){3}— ровно 3 раза{2,5}— от 2 до 5 раз включительно{3,}— 3 или более раз
По умолчанию квантификаторы жадные — они захватывают как можно больше. Добавление ? после квантификатора делает его ленивым: .*? захватывает как можно меньше. Это различие важно при извлечении контента между разделителями.
Якоря
Якоря не совпадают с символами; они совпадают с позициями в строке.
^— начало строки (или начало строки в многострочном режиме)$— конец строки (или конец строки в многострочном режиме)\b— граница слова — позиция между словесным и несловесным символом
Якоря необходимы для валидации. Без них паттерн \d+ совпал бы с цифрами внутри «abc123xyz». С якорями — ^\d+$ — он совпадает только со строками, состоящими исключительно из цифр.
Группы и чередование
Скобки создают захватывающие группы. Они служат двум целям: группировке подвыражения для применения квантификатора ко всей группе и захвату совпавшей подстроки для извлечения.
// Group with quantifier: match one or more "ab" repetitions
/(ab)+/ → matches "ab", "abab", "ababab"
// Alternation with |: match "cat" or "dog"
/(cat|dog)/ → matches "I have a cat" and "I have a dog"
// Named capture group
/(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/Незахватывающие группы — (?:...) — группируют без захвата, что чище, когда нужна только группировка без извлечения совпавшего текста.
Практические примеры
Валидация email
/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,}$/Разбор: ^ привязывает к началу. [a-zA-Z0-9._%+-]+ совпадает с локальной частью (один или более допустимых символов). @ — буквальный символ «@». [a-zA-Z0-9.-]+ совпадает с доменным именем. \. — буквальная точка (экранированная, так как неэкранированная . означает «любой символ»). [a-zA-Z]{2,} совпадает с доменом верхнего уровня длиной не менее 2 букв. $ привязывает к концу.
Номер телефона (формат США)
/^+?1?s?((?d{3})?[s.-]?)(d{3}[s.-]?d{4})$/Совпадает с форматами вроде 555-867-5309, (555) 867-5309, +1 555 867 5309 и 5558675309. Ключевой приём — использование ? для необязательных разделителей и группировки кода города с необязательными скобками.
Извлечение URL из текста
/https?://[^s"'<>]+/g
https? совпадает с «http» и «https» (символ s необязателен). :\/\/ совпадает с буквальным «://» с экранированными косыми чертами. [^\s"'<>]+ совпадает со всем, что не является пробелом или типичными завершающими символами URL. Флаг g находит все совпадения, а не только первое.
Флаги регулярных выражений
Флаги изменяют применение всего паттерна.
g(глобальный) — находит все совпадения, а не только первоеi(без учёта регистра) — рассматривает верхний и нижний регистр как эквивалентные;/hello/iсовпадает с «Hello», «HELLO» и «hello»m(многострочный) — заставляет^и$совпадать с началом/концом каждой строки, а не всей строки целикомs(dotAll) — заставляет.также совпадать с символами новой строки, полезно для совпадения через разрывы строк
В JavaScript флаги идут после закрывающей косой черты: /pattern/gi. В Python они передаются вторым аргументом: re.findall(pattern, text, re.IGNORECASE).
JavaScript vs Python: ключевые различия
Синтаксис регулярных выражений в основном одинаков в JavaScript и Python, но есть несколько важных отличий.
- Именованные группы: JavaScript использует
(?<name>...), Python — то же самое. Обе возвращают именованные группы, но доступ к ним различается —match.groups.nameв JS,match.group('name')в Python. - Просмотр вперёд/назад: обе поддерживают
(?=...)(положительный просмотр вперёд) и(?!...)(отрицательный). Python также поддерживает просмотры назад переменной длины; более старые движки JavaScript — нет. - Unicode: JavaScript требует флага
uдля обработки экранирований свойств Unicode вроде\p{Letter}. Модульreв Python обрабатывает Unicode по умолчанию. - Сырые строки: в Python всегда используйте сырые строки (
r"\d+"), чтобы избежать двойного экранирования. В JavaScript используйте либо литеральный синтаксис/\d+/, либо строку"\\d+"при конструировании черезnew RegExp().
Типичные ошибки в регулярных выражениях
- Катастрофический откат — паттерны вроде
(a+)+на несовпадающей строке могут вызвать экспоненциальный откат, блокируя движок. Избегайте вложенных квантификаторов для перекрывающихся паттернов. - Забытое экранирование точки —
3.14как паттерн совпадает с «3X14», потому что.— подстановочный символ. Используйте3\.14для совпадения с буквальной точкой. - Отсутствие якорей в паттернах валидации — без
^и$паттерн, предназначенный для валидации всей строки, совпадёт с любой строкой, содержащей паттерн как подстроку. - Использование регулярных выражений для разбора HTML — регулярные выражения не могут обрабатывать произвольно вложенные структуры. Используйте настоящий HTML-парсер (DOMParser в браузере, BeautifulSoup в Python) для разбора HTML.
Тестируйте паттерны безопасно в браузере
Писать регулярные выражения в редакторе без обратной связи — мучение. Написали паттерн, запустили код, увидели ошибку, поправили паттерн, запустили снова. Живой тестер регулярных выражений замыкает этот цикл — вы видите совпадения, подсвеченные в реальном времени по мере ввода.
Тестер регулярных выражений BrowseryTools позволяет написать паттерн, вставить тестовые строки и мгновенно увидеть все совпадения подсвеченными. Он работает полностью в браузере, так что вы можете тестировать на реальных данных — логах, пользовательском вводе, production-строках — без отправки чего-либо на сервер.
Итоги
Регулярные выражения окупают вложенное в их изучение время. Базовый словарь — классы символов, квантификаторы, якоря, группы и флаги — невелик. Паттерны, которые можно на его основе строить, — безграничны. Начните с примеров из этого руководства, тестируйте их на собственных строках, и синтаксис станет интуитивным быстрее, чем вы ожидаете.
Try the Tools — 100% Free, No Sign-Up
Everything runs in your browser. No uploads. No accounts. No ads.
Explore All Tools →