Перейти к основному содержимому

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


Для кого эта статья

Если вы ищете готовый regexp для email, проверки телефона, даты в тексте или фильтра лога — здесь собраны рабочие шаблоны с разбором каждого куска. Можно скопировать код в Python, JavaScript, HTML-форму или терминал. В shell — grep и пайплайны: Bash — однострочники и скрипты. Чтение лога из файла построчно на Python — Python — файлы и текст.

Статья рассчитана на:

  • школьников и студентов на первых лабораторных;
  • начинающих программистов, которым нужен шаблон «прямо сейчас»;
  • тех, кто хочет понять, что означает чужой regexp, а не просто вставить его.
Сначала теория — потом копирование

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

RegEx (regular expression, «регулярка») — короткая запись правила: «найди в тексте всё, что похоже на телефон» или «проверь, что пользователь ввёл email». Один шаблон заменяет десятки строк ручной проверки символов.

Загрузка интерактивного демо…

Вставьте шаблон из любого раздела ниже в поле «Шаблон» лаборатории и нажмите пресеты Email, Дата, Строка лога — так быстрее видно, как работает подсветка совпадений.


Как читать шаблон по частям

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

СимволНазваниеСмысл простыми словами
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

import re

def matches(pattern: str, text: str, flags: int = 0) -> bool:
"""True, если ВСЯ строка text подходит под pattern."""
return re.fullmatch(pattern, text, flags) is not None

def find_all(pattern: str, text: str, flags: int = 0) -> list[str]:
"""Список всех найденных фрагментов в text."""
return re.findall(pattern, text, flags)

def first_groups(pattern: str, text: str):
"""Первая строка лога → кортеж групп (date, time, ...)."""
m = re.match(pattern, text)
return m.groups() if m else None
ФункцияКогда использовать
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}$
ГруппаЧто попадёт в код
1916 — код оператора

Скобки (...) запоминают цифры — их можно взять через 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})$
Имя группыПримерЗачем
day22отдельно день
month01месяц
year2026год

Замена 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 33 строки контекста до и после

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]\d200–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 os1 → os
from json2 → 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.


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

ЗадачаКомандаПояснение
Найти ERRORgrep -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 rematch, search, sub
Bash =~условия в скриптах

См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").

Освоение главы0%