Регулярные выражения

Теория

Регулярное выражение — короткая запись шаблона текста: «две заглавные буквы, дефис, четыре цифры». С его помощью проверяют формат (артикул, телефон, промокод), находят нужные куски в тексте (номера заказов в логе), извлекают части и заменяют их. В Python для этого модуль re. Строковых методов (split, startswith, in) хватает для простых случаев; регулярное выражение нужно, когда структура текста сложнее «найти подстроку».

Шаблоны пишут в сырых строках r"...", чтобы обратный слеш (\d — цифра) не обрабатывался самим Python. Главная путаница — между функциями: re.fullmatch проверяет, что вся строка подходит под шаблон, re.search ищет совпадение где угодно внутри, re.findall возвращает все совпадения, re.sub заменяет. Для проверки формата нужен fullmatch — иначе «мусор» вокруг правильного фрагмента пройдёт проверку. Регулярки легко сделать нечитаемыми: если шаблон не помещается в голове, лучше разбить задачу или обойтись методами строк.

Наглядно

Таблица 1. Основные элементы шаблона.

Элемент Значит Пример Совпадает с
\d, \D цифра, не цифра \d{4} 0142
\w, \s буква/цифра/_, пробельный символ \w+ SALE10
[A-Z], [^0-9] символ из набора, не из набора [A-Z]{2} KB
. любой символ (кроме перевода строки) a.c abc, a-c
\. именно точка \d+\.\d{2} 1499.90
{n}, {n,m}, +, *, ? повторения: ровно n, от n до m, 1+, 0+, 0 или 1 \d{1,3} 7, 42, 100
^, $ начало и конец строки ^SALE SALE10
( ) группа — часть, которую можно извлечь №(\d+) №1042 → 1042
*?, +? «ленивое» повторение — как можно меньше "(.*?)" каждое значение в кавычках отдельно

Таблица 2. Функции модуля re.

Функция Что делает Результат
re.fullmatch(p, s) вся строка соответствует шаблону объект совпадения или None
re.search(p, s) первое совпадение где угодно объект совпадения или None
re.findall(p, s) все совпадения список строк (или групп)
re.sub(p, repl, s) заменить все совпадения новая строка
m.group(1) содержимое группы совпадения строка

На практике

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

Шаг 1. Проверяем формат целиком

Артикул: две заглавные латинские буквы, дефис, четыре цифры, дефис, три буквы цвета:

python
import re

SKU = r"[A-Z]{2}-\d{4}-[A-Z]{3}"
for sku in ("KB-0142-BLK", "kb-0142-blk", "KB-142-BLK"):
    print(sku, bool(re.fullmatch(SKU, sku)))

Результат:

вывод
KB-0142-BLK True
kb-0142-blk False
KB-142-BLK False

Шаг 2. Отличаем search от fullmatch

search ищет подходящий кусок где угодно — для проверки формата это дыра:

python
bad = "XXKB-0142-BLK!!"
print(bool(re.search(SKU, bad)), bool(re.fullmatch(SKU, bad)))

Результат:

вывод
True False

Шаг 3. Извлекаем части группами

Скобки выделяют группы — их содержимое можно достать после совпадения:

python
m = re.fullmatch(r"([A-Z]{2})-(\d{4})-([A-Z]{3})", "KB-0142-BLK")
print(m.group(1), m.group(2), m.group(3))
print(int(m.group(2)))

Результат:

вывод
KB 0142 BLK
142

Группы всегда возвращают строки — число получают явным int().

Шаг 4. Находим все совпадения

Номера заказов из строки лога. С одной группой findall возвращает содержимое групп:

python
log = "заказ №1042 оплачен; заказ №1043 отменён; возврат по №1040"
print(re.findall(r"№(\d+)", log))

Результат:

вывод
['1042', '1043', '1040']

Шаг 5. Заменяем лишнее

Телефон из формы приводим к виду «только цифры» — заменяем всё, что не цифра, на пустую строку:

python
for phone in ("+7 (912) 345-67-89", "8-912-345-67-89"):
    print(re.sub(r"\D", "", phone))

Результат:

вывод
79123456789
89123456789

Шаг 6. Экранируем специальные символы

Точка в шаблоне — «любой символ». Чтобы найти именно точку, её экранируют:

python
for price in ("1499.90", "1499,90", "1499x90"):
    print(price, bool(re.fullmatch(r"\d+.\d{2}", price)), bool(re.fullmatch(r"\d+\.\d{2}", price)))

Результат:

вывод
1499.90 True True
1499,90 True False
1499x90 True False

Шаг 7. Ограничиваем жадность

.* захватывает как можно больше — до последней подходящей кавычки. .*? — как можно меньше:

python
text = 'В корзине "Мышь" и "Коврик"'
print(re.findall(r'"(.*)"', text))
print(re.findall(r'"(.*?)"', text))

Результат:

вывод
['Мышь" и "Коврик']
['Мышь', 'Коврик']

Частые ошибки

  • search для проверки формата. Пропускает строки с мусором вокруг правильного фрагмента. Для проверки — fullmatch.
  • Неэкранированная точка. \d+.\d{2} принимает 1499,90 и 1499x90. Нужна \..
  • Жадное .*. Захватывает до последнего совпадения — сразу несколько значений. Используйте .*? или более точный набор ([^"]*).
  • Строка без r. "\d" пока работает, но Python предупреждает о неизвестной escape-последовательности, а "\b" — это символ backspace, а не граница слова. Шаблоны — всегда r"...".
  • Число из группы. m.group(2) — строка "0142"; для вычислений нужен int().
  • Регулярка для всего. Email, URL, HTML честно разбираются только специальными инструментами; для простых задач хватает методов строк.

Итог

Шаблоны

  • Сырые строки r"..."; \d, \w, \s, наборы [...], повторения {n,m}, +, *, ?.
  • . — любой символ; точка как символ — \..
  • Группы ( ) выделяют извлекаемые части; *? — ленивое повторение.

Функции

  • fullmatch — проверка формата всей строки; search — поиск где угодно.
  • findall — все совпадения (с группой — содержимое группы); sub — замена.
  • Результат групп — строки.

Меры предосторожности

  • Для проверки — только fullmatch.
  • Сложный шаблон — повод упростить задачу.

Вопросы на собеседовании

Чем re.match, re.search и re.fullmatch отличаются?

search ищет совпадение в любом месте строки, match — только с начала строки (но не обязательно до конца), fullmatch — требует, чтобы под шаблон подходила вся строка. Для проверки формата нужен fullmatch.

Что такое жадные и ленивые квантификаторы?

Жадные (*, +) захватывают как можно больше символов, ленивые (*?, +?) — как можно меньше. На "a" и "b" шаблон "(.*)" захватит a" и "b, а "(.*?)" — отдельно a и b.

Зачем писать шаблоны в сырых строках?

В обычной строке Python сам обрабатывает обратный слеш: "\b" превратится в символ backspace, а не в границу слова, "\d" вызовет предупреждение. В сырой строке r"\b" обратный слеш доходит до модуля re как есть.

Ошибка в тексте

Сообщить об ошибке могут зарегистрированные пользователи — так в сообщениях меньше спама.

Войти, чтобы сообщить