Регулярные выражения — синтаксис с нуля
Предыдущий шаг: введение и лаборатория.
Следующий: группы и замена.
Готовые шаблоны для работы — в рецептах и командной строке и лаборатории с разбором по блокам.
Зачем отдельная статья про синтаксис
Регулярное выражение — это мини-язык внутри строки. Один пропущенный \ или якорь $ меняет смысл с "проверить email" на "найти @ где угодно". Здесь разбирается алфавит этого языка: из чего собирают шаблон, как его читать слева направо и как по шагам проверять себя на реальных строках.
После этой статьи вы сможете:
- читать чужой шаблон по блокам, а не "узнавать целиком";
- отличать поиск подстроки от проверки всей строки;
- собирать маски для логина, даты, времени, пути к файлу;
- понимать, когда пора перейти к группам и флагам.
На каждый новый символ (\d, ^, {2,5}) сразу вбивайте мини-шаблон в лаборатории или на regex101.com. Теория без пяти строк текста в поле "Тест" почти не запоминается.
Как движок "читает" текст
Представьте указатель на символе строки и указатель на символе шаблона. Оба двигаются слева направо. Шаблон либо совпадает с текущим фрагментом текста, либо движок откатывается и пробует начать совпадение с следующей позиции в строке.
Строка для примеров:
user_12 вошёл в систему
| Шаблон | Что происходит | Результат |
|---|---|---|
user | буквы u→s→e→r подряд | совпадение user |
User | регистр другой | нет (без флага i) |
user | поиск с позиции после user_12 | нет на этом месте; движок мог найти раньше |
Шаблон user в тексте xuser_y тоже найдёт подстроку user внутри слова. Чтобы искать отдельное слово, позже понадобятся границы \b или якоря.
Первое совпадение — не всегда "самое логичное" для человека: движок берёт самое левое успешное. Для всех вхождений нужен флаг g или цикл в коде — флаги и жадность.
Пошаговая сборка шаблона
Удобный порядок работы (тот же применяют в Регулярные выражения — рецепты и командная строка):
- Словами — что считается успехом? "Строка целиком — дата" или "в логе есть ERROR".
- Якоря — нужны ли
^и$(форма) или поиск подстроки (лог). - Литералы — фиксированный текст:
[,@,://. - Классы — "цифра", "буква", "не пробел".
- Квантификаторы — сколько раз повторять.
- Проверка — 5–10 реальных строк + 2 "злых" (пустая, с пробелом, кириллица).
| Задача | Якоря | Типичный каркас |
|---|---|---|
| Поле формы | ^ … $ | ^[...]{мин,макс}$ |
| Поиск в файле | нет | литералы + классы |
| Одна строка лога целиком | ^ … $ | дата + время + уровень + сообщение |
Литералы — "ищи как написано"
Литерал — символ, который в данном месте шаблона означает "найди такой же символ в тексте". Обычно это буквы, цифры и часть знаков препинания.
| Шаблон | Текст | Результат |
|---|---|---|
12 | user_12 | 12 внутри слова |
_ | user_12 | подчёркивание |
вошёл | user_12 вошёл в систему | кириллица как литералы |
Какие символы экранировать
В шаблоне спецсимволы имеют отдельный смысл (см. экранирование). В литеральном фрагменте их пишут с \ или помещают в класс [...].
| Символ | Зачем экранировать |
|---|---|
. * + ? ^ $ [ ] ( ) { } | \ | управляющий смысл в regex |
- | внутри [ ] может означать диапазон |
# | в некоторых оболочках — комментарий (зависит от движка) |
В коде обратный слэш сам по себе спецсимвол: строка "\d" в Python — это символ d с предупреждением. Используйте сырые строки r"\d" / @"\d" — подробнее в конце статьи.
Точка . — "любой один символ"
. = ровно один символ, кроме перевода строки \n (если не включён флаг s — Регулярные выражения — флаги и жадность).
| Шаблон | Текст | Что найдёт |
|---|---|---|
u.er | user | user (s — "любой один") |
u.er | u_er | u_er |
u.er | uer | нет (нужен ровно один символ между u и er) |
Точка не означает "сколько угодно символов". Для нуля и более повторений — *, для одного и более — +.
Чтобы найти настоящую точку (IP, расширение файла), пишут \..
| Ошибка | Шаблон | Текст 3.14 |
|---|---|---|
| Точка как "любой" | \d.\d+ | подойдёт и 3x14 |
| Точка как литерал | \d\.\d+ | только с точкой |
Класс символов [ ... ]
В квадратных скобках задают один допустимый символ на текущей позиции.
| Шаблон | Смысл |
|---|---|
[abc] | a, b или c |
[a-z] | строчная латинская буква |
[A-Za-z0-9] | буква или цифра |
[._-] | точка, подчёркивание или дефис |
[0-9] | то же, что \d в ASCII-цифрах |
Пример: [Tt]he — The или the.
Внутри [ ] точка — обычная точка. Шаблон ar[.] ищет a, r и ..
Дефис в классе
- между двумя символами задаёт диапазон:
| Запись | Смысл |
|---|---|
[a-z] | от a до z |
[A-Z] | заглавные латинские |
[0-9] | цифры |
Чтобы искать буквальный дефис, поставьте его в начало или конец класса: [-az] или [az-].
Отрицание — [^ ... ]
^ сразу после [ — "любой один символ, кроме перечисленных":
| Шаблон | Смысл |
|---|---|
[^0-9] | всё, кроме цифры |
[^@\s]+ | подряд символы без @ и без пробела |
[^\n]+ | строка до перевода строки (упрощённо "всё до \n") |
^ в начале всего шаблона — "начало строки". ^ сразу после [ — "не этот набор". Это разные роли одного знака.
Когда класс лучше точки
| Задача | Слабо | Надёжнее |
|---|---|---|
| Содержимое HTML-тега | <.*> | <[^>]+> |
| До пробела | .* | [^\s]+ |
| Только буквы | .* | [A-Za-z]+ |
Сокращения \d, \w, \s и "отрицания"
| Код | Обычно значит | Пример |
|---|---|---|
\d | цифра 0–9 | \d{4} → год |
\w | буква, цифра, _ (часто только ASCII) | \w+ → user_12 |
\s | пробел, таб, перевод строки | \s+ → пробелы |
\D | не цифра | |
\W | не "слово" | |
\S | не пробел | \S+ → "слово" без пробелов |
Кириллица: \w в JavaScript не совпадает с п или ё. Для русского текста:
[а-яА-ЯёЁ0-9_]+
В JavaScript с флагом u — Unicode-классы \p{L} (буква), \p{N} (число). Проверяйте в лаборатории на своих строках.
| Текст | \w+ | [а-яА-ЯёЁ]+ |
|---|---|---|
привет | часто нет | да |
user_12 | да | только user без _12 при чисто кириллическом классе |
Для смешанного логина используйте явный объединённый класс: [A-Za-zа-яА-ЯёЁ0-9_]+.
Квантификаторы — "сколько раз повторять"
Квантификатор относится к предыдущему атому — одному символу, классу или (позже) группе.
| Символ | Сколько раз | Пример | Подходит к |
|---|---|---|---|
* | 0 и больше | ab*c | ac, abc, abbc |
+ | 1 и больше | ab+c | abc, не ac |
? | 0 или 1 | colou?r | color, colour |
{3} | ровно 3 | \d{3} | 123 |
{2,4} | от 2 до 4 | \d{2,4} | 12, 1234 |
{2,} | 2 и больше | \d{2,} | 99, 12345 |
{,6} | до 6 | .{,6} | не более 6 любых символов |
Пример: [a-z]* — ноль или больше строчных латинских букв.
.* — ноль или больше любых символов; по умолчанию жадно (тянет максимум). Подробно — Регулярные выражения — флаги и жадность.
Жадность на пальцах
Текст: aaa, шаблон a+ — совпадение aaa (все три). Шаблон a+? — ленивый, минимум; для одной буквы a результат тот же, разница видна на .* между маркерами.
Пустые совпадения
a* на тексте bbb даёт нулевое совпадение в начале (ноль букв a). В коде при подсчёте всех match это иногда удивляет — смотрите документацию движка.
Якоря ^ и $
| Символ | Смысл |
|---|---|
^ | начало строки (с флагом m — начало каждой строки в тексте) |
$ | конец строки |
Без якорей шаблон ищет подстроку. С якорями на всём шаблоне — всю строку целиком (валидация поля).
| Шаблон | Строка | Результат |
|---|---|---|
ok | not ok | есть (ok внутри) |
^ok$ | not ok | нет |
^ok$ | ok | да |
^[0-9]+$ | 42 | нет (пробелы) |
^[0-9]+$ | 42 | да |
Для "строка без пробелов по краям" иногда пишут ^\S+$ или обрезают пробелы в коде до regex.
В .NET также встречаются \A (начало всего текста) и \Z (конец) — полезно при многострочных строках без флага m.
Экранирование \
| Нужен символ | В шаблоне |
|---|---|
| точка | \. |
| плюс | \+ |
| звёздочка | \* |
| вопрос | \? |
| скобки | $ $ \[ \] |
| слэш | \\ |
В коде Python
import re
# Плохо: "\d" — не цифра
re.search("\d+", "42")
# Хорошо:
re.search(r"\d+", "42")
В коде C#
Regex.IsMatch("42", @"\d+");
В редакторе (VS Code / Cursor)
В поле поиска с включённым regex один \ обычно достаточен: \d+.
Сквозной разбор — логин пользователя
Правила (упрощённо):
- от 3 до 16 символов;
- только латиница, цифры,
_и-; - первый символ — буква.
Шаблон:
^[a-z][a-z0-9_-]{2,15}$
| Часть | Значение |
|---|---|
^ | начало строки |
[a-z] | первая буква — строчная латинская |
[a-z0-9_-] | дальше буква, цифра, _ или - |
{2,15} | ещё от 2 до 15 символов (итого 3…16) |
$ | конец |
| Строка | Подходит? | Почему |
|---|---|---|
jo-hn_doe | да | |
john12 | да | |
Jo | нет | заглавная в начале |
ab | нет | 2 символа |
jo hn | нет | пробел |
admin | да | зарезервированные имена отсекают в бизнес-логике, не в regex |
Вариант с флагом i (первая буква любого регистра, остальное по правилам) — отдельный шаблон или нормализация в нижний регистр до проверки.
Сквозной разбор — пароль (только длина и символы)
Сложные правила ("цифра + спецсимвол") удобнее через проверки вокруг. Здесь — только длина и набор символов:
^[A-Za-z\d@$!%*?&]{8,32}$
| Часть | Значение |
|---|---|
{8,32} | от 8 до 32 символов |
| класс | разрешённые символы |
Цифру и спецсимвол добавят отдельными (?=.*\d) в статье Регулярные выражения — проверки вокруг совпадения.
Сквозной разбор — 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,} | точка и зона |
| Строка | Результат |
|---|---|
user@example.com | да |
user@example | нет (нет зоны) |
bad @mail.com | нет (пробел) |
x@y.co | да |
Полные RFC-правила в regex не помещаются разумно — для UI достаточно упрощения; для почтового сервера — проверка доставкой.
Сквозной разбор — дата ДД-ММ-ГГГГ
^\d{2}-\d{2}-\d{4}$
| Часть | Значение |
|---|---|
\d{2}-\d{2}-\d{4} | день, месяц, год с дефисами |
^ $ | вся строка |
| Строка | Подходит? |
|---|---|
22-01-2026 | да |
2-1-2026 | нет |
32-01-2026 | да по regex, нет по календарю |
Календарь (31.02) — в коде. Regex проверяет форму.
Год в двух цифрах (устаревший формат): ^\d{2}-\d{2}-\d{2}$ — осторожно с веком; лучше четыре цифры года.
Сквозной разбор — время ЧЧ:ММ:СС
^\d{2}:\d{2}:\d{2}$
| Строка | По regex | По смыслу |
|---|---|---|
14:30:05 | да | да |
25:00:00 | да | нет (часы) |
9:05:01 | нет | нужны ведущие нули 09:05:01 |
Строгая проверка часов 00-23 — отдельные классы или код:
^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$
(упрощённо, без учёта leap second).
Сквозной разбор — имя файла бэкапа
^data_\d{4}\.csv$
Подходит: data_2026.csv. Для поиска в списке файлов без привязки ко всей строке — уберите ^ $: data_\d{4}\.csv.
Сквозной разбор — путь
Unix-подобный файл:
^[A-Za-z0-9_./-]+$
Windows (без диска):
^[A-Za-z0-9_\\.\\-]+$
В реальных путях лучше pathlib / Path, а regex — для фильтра в логе ("похоже на .exe"):
\.exe$
Сквозной разбор — уровень в логе
2026-01-22 14:30:05 [ERROR] Connection timeout
Только слово ERROR в скобках:
\[ERROR\]
| Часть | Значение |
|---|---|
\[ \] | буквальные скобки |
Любой уровень — в Регулярные выражения — группы и замена: \[(INFO|WARN|ERROR)\]. Полная строка лога — в Регулярные выражения — рецепты и командная строка.
Сквозной разбор — номер заказа
Формат: ORD- + год + - + 4 цифры.
^ORD-\d{4}-\d{4}$
| Строка | Результат |
|---|---|
ORD-2026-0042 | да |
ORD-26-42 | нет |
Границы слова \b
Граница слова — переход между \w и "не \w" (пробел, знак препинания, начало/конец).
| Шаблон | Текст | Результат |
|---|---|---|
cat | category | совпадение внутри |
\bcat\b | category | нет |
\bcat\b | a cat. | да |
Для кириллицы \b ненадёжен — явные классы или lookaround из Регулярные выражения — проверки вокруг совпадения.
Альтернатива | — "или" (введение)
\b(ERROR|WARN|INFO)\b
| Шаблон | Смысл |
|---|---|
| `cat | dog` |
| `(T | t)he` |
https? | http или https (? у s, не |) |
Скобки задают границы: one|two|three против one|(two|three).
Приоритет элементов
| Шаблон | Читается как |
|---|---|
ab+ | a + один и более b |
(ab)+ | повторы пары ab |
[a-z]+ | одна и более букв из класса |
a{2,4} | от 2 до 4 букв a |
Квантификатор "липнет" к ближайшему слева элементу. Сомневаетесь — добавьте (...).
Unicode и национальные символы
[а-яА-ЯёЁ0-9_]+
JavaScript (флаг u):
/\p{L}+/u // буквы Unicode
Перед продакшеном — тест на реальных ФИО, адресах, логах.
Типичные ошибки на уровне синтаксиса
| Симптом | Причина | Исправление |
|---|---|---|
| Всё совпадает | . вместо \. | экранировать точку |
| "Пустой" match везде | * допускает 0 раз | + или {1,} |
| Форма пропускает мусор | нет $ | ^...$ |
| Находит внутри слова | нет \b | границы или якоря |
| Кириллица не ищется | \w только ASCII | явный класс |
| В коде "не работает" | забыли r"..." | сырая строка |
Упражнения (проверьте в лаборатории)
| № | Задача | Подсказка |
|---|---|---|
| 1 | Только цифры, 1–5 знаков | ^\d{1,5}$ |
| 2 | Слово error целиком | \berror\b + флаг i |
| 3 | Дата ГГГГ-ММ-ДД | поменять порядок блоков |
| 4 | Файл .log в конце строки | \.log$ |
| 5 | Текст до первого пробела | [^\s]+ |
Шпаргалка шага 1
| Задача | Идея шаблона |
|---|---|
| Точное слово | литералы: error |
| "Что-то между" | [^>]+ точнее, чем .* |
| Только цифры | ^\d+$ |
| Дата ДД-ММ-ГГГГ | ^\d{2}-\d{2}-\d{4}$ |
| Кусок до пробела | [^\s]+ |
| Время | ^\d{2}:\d{2}:\d{2}$ |
Потренируйтесь в лаборатории (пресеты Email и Дата). Готовые команды для терминала — Регулярные выражения — рецепты и командная строка.
Дальше: Группы и замена →