Regex — готовые паттерны

Приветствую! Здесь вы наверняка найдете, что ищете. Примеры в лаборатории рассчитаны на то, что мы разбираем что-то конкретное.

Текущая статья посвящена готовым регулярным выражениям с разбором по символам.

Поэтому за теорией по текущей теме вам — в энциклопедию. Если ещё не погружались, то маршрут прост:

  1. Основы
  2. Система и сеть
  3. Данные и разметка
  4. Код и разработка
  5. Языки
  6. Искусственный интеллект
  7. Проект
  8. Инфраструктура и безопасность
  9. Спин-офф

Обязательно пройдитесь.

А теперь приступим к нашему предмету.

Теория и соседние материалы

Полный справочник метасимволов — Регулярные выражения (RegEx).

Пошаговое чтение шаблона слева направо — синтаксис с нуля.

Интерактивная лаборатория — введение в RegEx.


Разбор шаблона по частям

Движок идёт слева направо по шаблону и по тексту. Шаблон собирают из «кирпичиков»:

Символ Название Смысл простыми словами
a, @, 7 литерал символ «как есть»
. точка любой один символ (кроме перевода строки)
\d «digit» одна цифра 09
\w «word» буква, цифра или _ (кириллица часто не входит)
\s «space» пробел, таб, перевод строки
[abc] класс один символ из набора a, b, c
[a-z] диапазон одна строчная латинская буква
* звёздочка предыдущий элемент 0 или больше раз
+ плюс предыдущий элемент 1 или больше раз
? вопрос предыдущий элемент 0 или 1 раз
{3} квантификатор ровно 3 раза
{2,5} квантификатор от 2 до 5 раз
^ карет начало строки
$ доллар конец строки
\b граница слова стык «буква ↔ не буква»
(..) группа запомнить кусок для извлечения или замены
| «или» левый вариант или правый
\ экранирование «следующий символ — буквально, не команда»

Два режима — запомните их в первую очередь:

Режим Якоря Когда
Проверка поля формы ^ в начале, $ в конце «вся строка целиком — email»
Поиск в тексте без ^ $ «найди все телефоны в абзаце»

Пример: шаблон ok найдёт ok внутри not ok really. Шаблон ^ok$ пройдёт только для строки ok.


Стартовые паттерны

Перед email и логами — пять простых шаблонов. Их часто дают на первых занятиях по Python или веб-разработке.


1. Только цифры

Задача: строка состоит только из цифр (номер группы, код, pin).

^\d+$
Часть Смысл
^ начало строки
\d одна цифра
+ одна цифра и дальше ещё сколько угодно
$ конец строки
Строка Результат
12345 да
007 да
12a34 нет
`` (пусто) нет — + требует хотя бы одну цифру

Python — полная программа:


import re

ONLY_DIGITS = r'^\d+$'

tests = ['12345', '12a34', '', '999']
for s in tests:
    ok = re.fullmatch(ONLY_DIGITS, s) is not None
    print(f'{s!r:10} -> {"OK" if ok else "нет"}')

Что делает код:

  1. import re — модуль регулярных выражений в Python.
  2. r'^\d+$' — сырая строка: обратные слэши не «съедаются» Python.
  3. re.fullmatch — проверка всей строки (аналог ^ $ внутри).
  4. Цикл прогоняет тестовые строки и печатает результат.

2. Только буквы (латиница)

Задача: имя пользователя без цифр и пробелов.

^[a-zA-Z]+$
Часть Смысл
[a-zA-Z] одна латинская буква (строчная или заглавная)
+ минимум одна буква, дальше — ещё
Строка Результат
Anna да
Иван нет — кириллица вне класса
Ann2 нет — цифра

Для русского имени: ^[а-яА-ЯёЁ]+$.


3. Логин — буквы, цифры, дефис, подчёркивание

Задача: от 3 до 16 символов, типичное поле «username».

^[a-zA-Z0-9_-]{3,16}$
Часть Смысл
[a-zA-Z0-9_-] буква, цифра, _ или -
{3,16} от 3 до 16 таких символов подряд
Строка Результат
user_12 да
ab нет — только 2 символа
very_long_login_name_99 нет — больше 16

JavaScript в браузере:

const LOGIN = /^[a-zA-Z0-9_-]{3,16}$/;

console.log(LOGIN.test('user_12'));  // true
console.log(LOGIN.test('ab'));       // false

/../ — литерал RegExp в JS. Метод .test() возвращает true или false.


4. Слово «Привет» в начале строки

Задача: строка начинается с «Привет» (регистр важен без флага i).

^Привет
Часть Смысл
^ начало строки
Привет шесть букв подряд
Строка Результат
Привет, мир! да — совпадение с позиции 0
Снова Привет нет — «Привет» не в начале

Без $ в конце шаблон ищет префикс, остаток строки не проверяется.


5. Найти все числа в тексте

Задача: из предложения вытащить все целые числа (без якорей — поиск фрагментов).

\b\d+\b
Часть Смысл
\b граница слова — число отделено от букв
\d+ одна или несколько цифр
\b конец «слова-числа»

Текст: Заказ №42 стоит 1500 рублей, скидка 10%

Совпадения: 42, 1500, 10


import re

text = 'Заказ №42 стоит 1500 рублей, скидка 10%'
numbers = re.findall(r'\b\d+\b', text)
print(numbers)  # ['42', '1500', '10']

findall возвращает список всех совпадений слева направо.


Каркас проверки — шаблон для любой задачи

Сохраните этот блок и подставляйте свой шаблон вместо YOUR_PATTERN.

Python

Функция Когда использовать
matches форма, пароль, «строка — email?»
find_all «все телефоны в тексте»
first_groups разбор одной строки лога на поля

JavaScript

/** Вся строка подходит под шаблон? */
function matches(pattern, text, flags = '') {
  return new RegExp(`^(?:${pattern})$`, flags).test(text);
}

/** Все совпадения в тексте */
function findAll(pattern, text, flags = 'g') {
  const f = flags.includes('g') ? flags : flags + 'g';
  return [..text.matchAll(new RegExp(pattern, f))].map((m) => m[0]);
}

(?:..) — группа без захвата: нужна только для скобок вокруг pattern, чтобы ^ и $ работали корректно.

HTML-форма — браузер проверяет поле до отправки на сервер:

<label>
  Email:
  <input
    type="email"
    name="contact"
    pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
    title="Пример: user@example.com"
    required
  >
</label>
Атрибут Зачем
type="email" базовая проверка браузером
pattern=".." ваш regexp (без / и флагов)
title текст подсказки при ошибке
required поле обязательно

Email

Задача: проверить адрес в форме или найти все @-строки в документе.

Проверка всей строки (форма)

^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

Разбор по блокам:

Блок Что означает
^ строка начинается здесь
[a-zA-Z0-9._%+-]+ локальная часть до @: буквы, цифры, . _ % + -, минимум 1 символ
@ символ «собака» буквально
[a-zA-Z0-9.-]+ домен: буквы, цифры, точка, дефис
\. точка перед зоной (экранирована — иначе . = «любой символ»)
[a-zA-Z]{2,} зона .com, .ru — минимум 2 буквы
$ строка заканчивается здесь

Визуально:

user.name+tag @ sub.domain . com
└─ локаль ─┘   └─ домен ─┘ └зона┘
Тест Ожидание Почему
user@example.com да классический адрес
a@b.co да короткая зона из 2 букв
user@.com нет пустой домен перед точкой
bad@@mail нет два @ подряд
xuser@example.comy нет при ^$ лишние символы по краям

Python:


import re

EMAIL = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'

print(re.fullmatch(EMAIL, 'contact@company.ru'))  # match object
print(re.fullmatch(EMAIL, 'bad@@mail'))          # None

JavaScript:

const EMAIL = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
EMAIL.test('contact@company.ru'); // true

Поиск email в абзаце

Уберите ^ и $ — шаблон найдёт адрес внутри текста:

[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
text = 'Пишите на admin@site.ru или support@help.org'
emails = re.findall(r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}', text)
# ['admin@site.ru', 'support@help.org']

Телефон +7 (Россия)

Задача: найти номер в тексте объявления или проверить строгий формат для CRM.

Гибкий поиск в тексте

\+7\s?\(?\d{3}\)?\s?\d{3}[-\s]?\d{2}[-\s]?\d{2}
Блок Смысл
\+7 плюс и семёрка (+ экранирован)
\s? необязательный пробел
\(? необязательная открывающая скобка (
\d{3} ровно 3 цифры (код оператора)
\)? необязательная )
\d{3} следующие 3 цифры
[-\s]? дефис или пробел — необязательно
\d&#123;2&#125;[-\s]?\d&#123;2&#125; две пары по 2 цифры

Пример текста: Звоните +7 (916) 555-12-34 или +79165551234

Найдёт оба варианта — со скобками и слитно.

PHONE = r'\+7\s?\(?\d{3}\)?\s?\d{3}[-\s]?\d{2}[-\s]?\d{2}'
text = 'Звоните +7 (916) 555-12-34 или +79165551234'
print(re.findall(PHONE, text))

Терминал (ripgrep):

rg -o '\+7\s?\(?\d{3}\)?\s?\d{3}[-\s]?\d{2}[-\s]?\d{2}' page.html

-o — вывести только совпавший фрагмент, без всей строки файла.

Строгий формат +7 916 555-12-34

^\+7\s(\d{3})\s\d{3}-\d{2}-\d{2}$
Группа Что попадёт в код
1 916 — код оператора

Скобки (..) запоминают цифры — их можно взять через m.group(1) в Python.


URL в тексте

Задача: вытащить ссылки из README или поста.

https?://[^\s<>"']+
Блок Смысл
https? http + необязательная shttp или https
:// буквально
[^\s<>"']+ один и более символов кроме пробела, <, >, ", '

Почему [^..]: «любой символ, кроме перечисленных» — ссылка обрывается на пробеле или кавычке HTML.

const URL = /https?:\/\/[^\s<>"']+/g;
const text = 'Документация: https://example.com/path?q=1 и старый http://test.local';
console.log(text.match(URL));
// ['https://example.com/path?q=1', 'http://test.local']

Флаг g — искать все совпадения, не только первое.


Даты и время

Гибкая дата в тексте

Задача: найти 22.01.2026, 22/01/26, 22-01-2026.

\b\d{1,2}[./-]\d{1,2}[./-]\d{2,4}\b
Блок Смысл
\b граница — дата не «приклеена» к буквам
\d{1,2} день: 1–2 цифры
[./-] разделитель — точка, слэш или дефис
\d{1,2} месяц
[./-] снова разделитель
\d{2,4} год: 2 или 4 цифры
Ограничение

Шаблон не проверяет, что 31.02 существует в календаре — только формат «цифры-разделитель-цифры».

Строго ДД-ММ-ГГГГ с именованными группами

^(?<day>\d{2})-(?<month>\d{2})-(?<year>\d{4})$
Имя группы Пример Зачем
day 22 отдельно день
month 01 месяц
year 2026 год

Замена 2026-01-2222.01.2026 — группы меняют местами:


import re

iso = '2026-01-22'
result = re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\3.\2.\1', iso)
print(result)  # 22.01.2026
В шаблоне В замене Откуда
1-я (..) \1 год
2-я (..) \2 месяц
3-я (..) \3 день
'2026-01-22'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3.$2.$1');
// '22.01.2026'

В JavaScript в замене — $1, $2, $3 (со знаком $, не \).

ISO-дата 2026-01-22

\b\d{4}-\d{2}-\d{2}\b

Четыре цифры года, дефис, две цифры месяца, дефис, две цифры дня.


Логи — разбор строки по полям

Пример строки:

2026-01-22 14:30:05 [ERROR] Connection timeout host=10.0.0.5

Шаблон целиком:

^(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})\s+\[(\w+)\]\s+(.+)$

Пошагово:

Шаг Шаблон Совпадает с
1 ^ начало строки
2 (\d&#123;4&#125;-\d&#123;2&#125;-\d&#123;2&#125;) группа 12026-01-22
3 \s+ один или более пробелов
4 (\d&#123;2&#125;:\d&#123;2&#125;:\d&#123;2&#125;) группа 214:30:05
5 \s+\[ пробелы и литерал [
6 (\w+) группа 3ERROR (буквы/цифры/_)
7 \]\s+ ] и пробелы
8 (.+) группа 4 — всё сообщение до конца
9 $ конец строки

Python — разбор одной строки:


import re

LOG = r'^(\d{4}-\d{2}-\d{2})\s+(\d{2}:\d{2}:\d{2})\s+\[(\w+)\]\s+(.+)$'
line = '2026-01-22 14:30:05 [ERROR] Connection timeout host=10.0.0.5'

m = re.match(LOG, line)
if m:
    date, time, level, message = m.groups()
    print(date, time, level)
    print('Сообщение:', message)

Фильтр только ERROR в терминале:

rg '\[(ERROR|WARN)\]' logs/
rg -C 3 '\[ERROR\]' application.log
Команда Эффект
(ERROR|WARN) уровень ERROR или WARN
-C 3 3 строки контекста до и после

IP в хвосте host=10.0.0.5:

host=(\d{1,3}(?:\.\d{1,3}){3})

(?:\.\d{1,3}){3} — три раза повторить «точка + 1–3 цифры» без отдельной группы.


IPv4, MAC, UUID

IPv4-адрес

\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b

Идея: один октет (число 0–255) — это одно из:

Альтернатива Диапазон
25[0-5] 250–255
2[0-4]\d 200–249
[01]?\d\d? 0–199

После октета идёт \. (точка), и весь блок {3} повторяется три раза — получается A.B.C.D.

IPV4 = r'\b(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\b'
text = 'Сервер 192.168.0.1, шлюз 10.0.0.1'
print(re.findall(IPV4, text))

MAC-адрес

\b(?:[0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b

Шесть пар hex-цифр через : или -: AA:BB:CC:DD:EE:FF.

UUID

\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b

Фиксированная структура 8-4-4-4-12 hex-символов с дефисами.


Пароль — проверка требований

Задача: минимум 8 символов, хотя бы одна буква и одна цифра.

^(?=.*[A-Za-z])(?=.*\d).{8,}$
Блок Смысл
(?=.*[A-Za-z]) lookahead — где-то в строке есть буква
(?=.*\d) где-то есть цифра
.{8,} любые 8+ символов от начала до $

Lookahead (?=..) смотрит вперёд, но не «съедает» символы — удобно для нескольких условий сразу.

Пароль Результат
Secret1 да
secret нет — нет цифры
12345678 нет — нет буквы
Ab1 нет — меньше 8 символов

Со спецсимволом:

^(?=.*[A-Za-z])(?=.*\d)(?=.*[!@#$%^&*]).{8,}$

Поиск в коде и конфигах

TODO и FIXME

\b(TODO|FIXME|HACK|XXX)\b
rg -n 'TODO|FIXME' --type py --type js

import в Python

^import\s+(\w+)|^from\s+(\w+)
Совпадение Группа
import os 1 → os
from json 2 → json

Ключ=значение в .env

^([a-zA-Z0-9_.-]+)=(.*)$

Пропустить строки-комментарии:

^(?!\s*#)([a-zA-Z0-9_.-]+)=(.*)$

(?!\s*#) — негативный lookahead: строка не начинается с #.


Замена и очистка — частые приёмы

Оставить только цифры (нормализация телефона)


import re

raw = '+7 (916) 555-12-34'
digits = re.sub(r'\D', '', raw)
print(digits)  # 79165551234
Часть Смысл
\D любой символ кроме цифры
'' заменить на пустоту — удалить
'+7 (916) 555-12-34'.replace(/\D/g, '');
// '79165551234'

Убрать лишние пробелы

re.sub(r'\s+', ' ', '  много   пробелов  ').strip()
# 'много пробелов'

Повтор слова (опечатка «ошибка ошибка»)

\b(\w+)\s+\1\b

\1 — «то же самое, что в 1-й группе». Для русского: \b([а-яА-ЯёЁ\w]+)\s+\1\b.


Шпаргалка терминала

Задача Команда Пояснение
Найти ERROR grep -E 'ERROR' file.log -E — расширенный regexp
Без регистра grep -Ei 'error' file.log -i — ignore case
Только совпадение grep -Eo 'pattern' file -o — output only match
По всему проекту rg 'pattern' . ripgrep, уважает .gitignore
Только имена файлов rg -l 'pattern' . где нашлось
Контекст rg -C 3 'ERROR' logs/ 3 строки до/после

Важно: в shell шаблон оборачивайте в одинарные кавычки '..', иначе bash съест $, \, !.


Типичные ошибки новичка

Ошибка Что происходит Как исправить
Забыли ^ $ в форме not-an-email-but-has@x.com-extra проходит якоря для «вся строка»
Точка без \ . совпадает с любым символом \. для буквальной точки
Жадный .* <div>A</div><div>B</div> — одно огромное совпадение .*? или [^>]*
\w для русского слово «Привет» не находится [а-яА-ЯёЁ]
\d в обычной Python-строке \d превращается в d префикс r'..'
JSON/HTML одним regexp ломается на вложенности json.loads, DOM

Жадный и ленивый квантификатор

Текст: <b>жирный</b>

Шаблон Что захватит
<.*> <b>жирный</b> целиком (жадный)
<.*?> <b> и отдельно </b> (ленивый)

? после * или + говорит «бери минимум символов».


Практика — три мини-задания

  1. Цифры. Напишите шаблон для строки ровно из 6 цифр (код из SMS). Подсказка: ^\d{6}$.
  2. Email. В лаборатории вставьте шаблон email и проверьте строку test@mail.ru и test@mail.
  3. Лог. Скопируйте строку лога из раздела выше, извлеките группу level в Python через .group(3).

Ответы и разбор — в синтаксисе с нуля и рецептах для терминала.


Чек-лист перед сдачей лабораторной или деплоем

  • Понятен режим — вся строка (^ $) или поиск фрагмента.
  • Прогнали 5 нормальных и 2 «злых» тестовых строки.
  • В Python использовали r'..' или двойные слэши \\d.
  • Для кириллицы явно указали [а-яА-ЯёЁ], а не \w.
  • JSON и HTML разбираете парсером, regexp — только для простых масок.

Связанные материалы

Материал Зачем открыть
RegEx — справочник все метасимволы и флаги
Синтаксис с нуля учебник по чтению шаблона
Рецепты и grep больше шаблонов + sed, awk
RegExp в JavaScript методы строк и флаги
Python re match, search, sub
Bash =~ условия в скриптах