Регулярные выражения - это переиспользуемые шаблоны для поиска и сопоставления последовательностей символов в тексте. Можно представить их как мощный инструмент поиска, который работает практически в любом языке программирования. Валидация email-адресов, очистка номеров телефонов из форм, парсинг лог-файлов - десяток грамотно подобранных regex-паттернов закроет 90% задач. В этом руководстве собраны самые практичные шаблоны с подробным разбором каждого.
Содержание
Краткий справочник по синтаксису
Прежде чем разбирать конкретные паттерны, полезно освежить в памяти базовые токены. Даже если ты уже работал с регулярными выражениями, иметь всё это в одном месте удобно.
| Токен | Значение | Пример совпадения |
|---|---|---|
.
|
Любой символ, кроме перевода строки |
a.c
совпадает с
abc
,
a1c
|
\d
|
Любая цифра (0-9) |
\d\d
совпадает с
42
|
\w
|
Словесный символ (буквы, цифры, знак подчёркивания) |
\w+
совпадает с
hello_world
|
\s
|
Пробельный символ (пробел, табуляция, перевод строки) |
\s+
совпадает с несколькими пробелами
|
^
/
$
|
Начало / конец строки |
^\d+$
совпадает только с
123
|
{n,m}
|
От n до m повторений |
\d{2,4}
совпадает от
12
до
1234
|
[abc]
|
Класс символов - любой из a, b, c |
[aeiou]
совпадает с любой гласной
|
(?:...)
|
Незахватывающая группа | Группирует без сохранения обратной ссылки |
(?=...)
|
Позитивный lookahead | Проверяет, что следует дальше, не потребляя символы |
Руководство по регулярным выражениям на MDN Web Docs - лучший единый справочник по regex-синтаксису JavaScript. Большинство паттернов ниже напрямую переносятся в Python, PHP, Java и Ruby с незначительными различиями в флагах.
Валидация email
Email - классический сценарий применения regex, и именно здесь большинство разработчиков допускают ошибку, пытаясь сделать паттерн слишком строгим. Спецификация
RFC 5322
технически допускает адреса вроде
"very unusual"@example.com
, с которыми почти ни один regex не справится. Для 99% задач валидации пользовательского ввода достаточно прагматичного паттерна:
^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$
Что делает каждая часть:
-
[a-zA-Z0-9._%+\-]+- локальная часть (до символа @); допускает точки, знаки плюса, дефисы, подчёркивания -
@- символ @ буквально -
[a-zA-Z0-9.\-]+- доменное имя, включая поддомены -
\.[a-zA-Z]{2,}- TLD длиной не менее 2 символов (.io, .com, .museum)
URL и веб-адреса
Паттерны для URL нужны как для извлечения ссылок из обычного текста, так и для валидации поля с сайтом, которое заполняет пользователь.
https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_+.~#?&\/=]*)
-
https?- совпадает как сhttp, так и сhttps -
(?:www\.)?- необязательный префикс www -
[-a-zA-Z0-9@:%._+~#=]{1,256}- символы имени хоста, до 256 символов -
\.[a-zA-Z0-9()]{1,6}- TLD -
\b(?:[-a-zA-Z0-9()@:%_+.~#?&\/=]*)- необязательные путь, строка запроса и фрагмент
Если нужна только валидация (без извлечения), оберни паттерн якорями
^
и
$
.
Номера телефонов
Номера телефонов - заведомо неудобный случай, потому что форматирование сильно варьируется в зависимости от страны и привычек пользователя. Два паттерна покрывают большинство сценариев:
Формат США/Канады (NANP)
^(\+1[-.\s]?)?(\(?\d{3}\)?[-.\s]?)?\d{3}[-.\s]?\d{4}$
Совпадает с:
555-867-5309
,
(555) 867 5309
,
+1.555.867.5309
,
5558675309
Международный формат (E.164)
^\+[1-9]\d{6,14}$
E.164 - это формат, который используется в большинстве телефонных API (Twilio, AWS SNS). Начинается с
+
и кода страны, без пробелов и знаков препинания.
Даты и время
Паттерны для дат часто встречаются в парсерах логов, валидаторах форм и пайплайнах обработки данных. Нужный формат зависит от источника входных данных.
ISO 8601 (YYYY-MM-DD)
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
Американский формат (MM/DD/YYYY)
^(0[1-9]|1[0-2])\/(0[1-9]|[12]\d|3[01])\/\d{4}$
24-часовое время (HH:MM или HH:MM:SS)
^([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?$
Обрати внимание: эти паттерны проверяют формат, но не календарную логику. Например,
2024-02-31
(31 февраля) пройдёт валидацию. Для строгой проверки дат разбирай значение средствами стандартной библиотеки дат уже после проверки regex.
Проверка надёжности пароля
Требования к паролям обычно включают сочетание разных типов символов и минимальную длину. Lookahead-ы позволяют сделать это чисто, без нескольких отдельных проверок.
Минимум 8 символов, хотя бы одна заглавная, одна строчная буква и одна цифра
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$
Надёжный: 8+ символов, заглавные, строчные буквы, цифра и специальный символ
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]).{8,}$
Каждый
(?=.*[...])
- это lookahead, который просматривает всю строку в поисках хотя бы одного подходящего символа. Финальный
.{8,}
задаёт минимальную длину. Можно заменить
{8,}
на
{12,}
для требования минимум 12 символов - это соответствует рекомендациям
NIST SP 800-63B
.
IP-адреса
IPv4
^(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)$
Паттерн корректно отклоняет значения вроде
999.0.0.1
, явно сопоставляя каждый октет в диапазоне 0-255.
IPv6 (упрощённый вариант)
^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$
Обрабатывает полный формат из 8 групп. Для сжатой нотации (например,
::1
для loopback) паттерн значительно усложняется - в таком случае надёжнее воспользоваться сетевой библиотекой, а не regex.
HTML и разметка
Для HTML есть несколько действительно полезных точечных паттернов. Общий совет «не парси HTML с помощью regex» по-прежнему актуален для полных документов - для этого используй нормальный DOM-парсер, например BeautifulSoup или DOMParser. Но для конкретных, ограниченных задач regex вполне справится.
Удалить все HTML-теги
<[^>]*>
Извлечь содержимое конкретного тега (например, <title>)
([^<]*)<\/title>
Захватывающая группа 1 содержит текст заголовка.
Сопоставить hex-коды цветов HTML
#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})\b
Совпадает как с трёхсимвольным сокращением (
#fff
), так и с полной шестисимвольной записью (
#ffffff
).
Универсальные утилитарные паттерны
Эти паттерны постоянно встречаются в самых разных проектах.
Slug (строка, пригодная для URL)
^[a-z0-9]+(?:-[a-z0-9]+)*$
Совпадает со строками вроде
my-blog-post-2024
. Без заглавных букв, без дефисов в начале и конце, без двойных дефисов.
Номер банковской карты (базовый формат, без пробелов)
^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12})$
-
Начинается с
4- Visa (13 или 16 цифр) -
Начинается с
51-55- Mastercard (16 цифр) -
Начинается с
34или37- Amex (15 цифр) -
Начинается с
6011или65- Discover (16 цифр)
Нормализация пробелов (сворачивание нескольких пробелов в один)
\s{2,}
Заменяй совпадения одним пробелом, чтобы очистить неаккуратный пользовательский ввод или спарсенный текст.
Только цифры
^\d+$
Только буквенно-цифровые символы
^[a-zA-Z0-9]+$
Поиск строки, содержащей слово (без учёта регистра с флагом)
^.*\bword\b.*$
Граница слова
\b
предотвращает совпадение
word
внутри
password
.
Извлечение номеров версий (semver)
\bv?(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.]+))?(?:\+([a-zA-Z0-9.]+))?\b
Захватывает мажорную, минорную, патч-версию, метку пре-релиза и метаданные сборки из строк вроде
v2.14.0-beta.1+build.42
.
Флаги и практические советы
Поведение regex-паттернов зависит от применяемых флагов. Вот наиболее востребованные из них:
| Флаг | JS | Python | Эффект |
|---|---|---|---|
| Без учёта регистра |
i
|
re.IGNORECASE
|
Считает заглавные и строчные буквы одинаковыми |
| Глобальный (найти все) |
g
|
re.findall()
|
Возвращает все совпадения, а не только первое |
| Многострочный |
m
|
re.MULTILINE
|
^
и
$
привязываются к границам строк, а не всей строки целиком
|
| Dotall |
s
|
re.DOTALL
|
.
совпадает в том числе с символами перевода строки
|
Несколько привычек, которые сэкономят время при отладке:
- Всегда тестируй на граничных случаях - пустая строка, максимальная длина, Unicode-символы и строки, которые почти, но не совсем валидны.
-
Используй незахватывающие группы
(?:...), когда содержимое совпадения не нужно - это быстрее и чище, чем захватывающие группы. -
Закрепляй паттерны для валидации
якорями
^и$, чтобы валидная подстрока внутри невалидной строки не проскользнула незамеченной. -
Остерегайся катастрофического backtracking-а
- вложенные квантификаторы вроде
(a+)+могут привести к зависанию regex-движка на специально подобранных входных данных. Держи квантификаторы простыми и конкретными. - Используй онлайн-тестер regex при построении паттернов. regex101.com показывает разбор совпадений в реальном времени, объясняет каждый токен и позволяет переключаться между PCRE, JavaScript, Python и другими диалектами.
Тестируй и проверяй regex-паттерны без лишних догадок
Создавать надёжные regex-паттерны для валидации ввода гораздо быстрее, когда под рукой есть нужные инструменты. Попробуй наши бесплатные утилиты для разработчиков - очищай, проверяй и преобразовывай текст с помощью regex-паттернов и не только.
Попробовать бесплатные инструменты →
Жадные квантификаторы (например,
.*
) захватывают как можно больше символов, а затем откатываются назад. Ленивые квантификаторы (например,
.*?
) захватывают как можно меньше. Например, для строки
bold
паттерн
<.*>
совпадает со всей строкой, тогда как
<.*?>
совпадает только с
. Используй ленивые квантификаторы при извлечении содержимого между разделителями.
В основном да, но различия есть. Модуль
re
в Python использует синтаксис в стиле PCRE и поддерживает именованные группы через
(?P
. JavaScript использует немного другой синтаксис флагов и не поддерживает lookbehind в старых движках (до ES2018). Для кроссплатформенного кода придерживайся общего подмножества: классы символов, квантификаторы, якоря и базовые группы.
Regex вполне подходит для валидации формата в продакшене - он используется практически в каждом веб-фреймворке. Риски связаны с плохо написанными паттернами, которые допускают ReDoS-атаки (отказ в обслуживании через regex) за счёт катастрофического backtracking-а. Избегай вложенных квантификаторов, делай паттерны конкретными и всегда устанавливай разумное ограничение длины входных данных до запуска regex.
В большинстве распространённых движков они эквивалентны для ASCII-ввода. Разница проявляется при работе с Unicode:
\d
в некоторых движках (например, Python 3 в режиме Unicode) совпадает с цифрами из других систем письма, в частности с арабско-индийскими цифрами. Если нужны строго ASCII-цифры от 0 до 9, используй
[0-9]
для однозначности. Для большинства задач валидации веб-форм это различие несущественно.
Нужны две вещи: флаг
dotall
(чтобы
.
совпадал с переводами строк) и, возможно, флаг
multiline
(чтобы
^
и
$
привязывались к каждой строке, а не ко всей строке целиком). В JavaScript используй
/pattern/ms
. В Python комбинируй
re.DOTALL | re.MULTILINE
. Без dotall символ
.
останавливается на переводах строк и паттерн не охватит несколько строк.