Программирование и IT

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

Регулярное выражение — шаблон, описывающий множество строк. В Python с ними работает модуль `re` из стандартной библиотеки. Шаблон пишут в строке с префиксом `r`, ищут через `re.search`, а результат достают из объекта совпадения. Всё остальное — детали языка шаблонов.

Обновлено
В этой статье

Когда шаблон уместен#

Регулярка выигрывает там, где структура текста нечёткая: выдернуть все даты из
абзаца, проверить формат кода, найти повторяющиеся пробелы. Если же строка
разделена запятыми или табуляцией, обычный split быстрее, читается лучше и
не ломается от лишней скобки — смотри разбор
строковых методов. Разбирать регуляркой HTML или JSON
не стоит вовсе: для них есть готовые библиотеки.

Первый поиск#

import re

text = "заказ 1207 от 21.09.2026"
m = re.search(r"\d+", text)
print(m.group())        # 1207
print(m.span())         # (6, 10)
print(re.findall(r"\d+", text))   # ['1207', '21', '09', '2026']

Префикс r перед строкой отключает обработку обратных слэшей самим Python:
без него "\d" пришлось бы писать как "\\d". Привыкай ставить r всегда.

Четыре функции покрывают почти всё:

  • re.search — первое совпадение в любом месте строки, иначе None;
  • re.match — совпадение только с начала строки;
  • re.fullmatch — вся строка целиком;
  • re.findall — список всех совпадений.
print(re.match(r"\d+", text))              # None — строка начинается с буквы
print(bool(re.fullmatch(r"\d{4}", "2026")))  # True

Путаница search и match — самая частая причина «шаблон правильный, а не
находит».

Из чего состоит шаблон#

Запись Значение
. любой символ, кроме перевода строки
\d \w \s цифра, буква или цифра или _, пробельный символ
\D \W \S то же с отрицанием
[абв] [а-я] любой символ из набора или диапазона
[^абв] любой символ вне набора
* + ? ноль и больше, один и больше, ноль или один
{2} {2,5} ровно два, от двух до пяти
^ $ начало и конец строки
| или
(...) группа, её содержимое достаётся отдельно

В Python 3 шаблон по умолчанию работает с Unicode, поэтому \w находит и
кириллицу: re.findall(r"\w+", "мама мыла раму") вернёт все три слова.

Группы дают доступ к частям совпадения:

m = re.search(r"(\d{2})\.(\d{2})\.(\d{4})", "срок до 21.09.2026 включительно")
print(m.group(0))    # 21.09.2026
print(m.group(1))    # 21
print(m.groups())    # ('21', '09', '2026')

named = re.search(r"(?P<day>\d{2})\.(?P<month>\d{2})", "01.02")
print(named.group("month"))   # 02

Жадность — главная ловушка#

Квантификаторы по умолчанию жадные: берут как можно больше, а потом отдают
назад ровно столько, сколько нужно для совпадения.

s = "<b>жирный</b> и <i>курсив</i>"
print(re.findall(r"<.*>", s))    # ['<b>жирный</b> и <i>курсив</i>']
print(re.findall(r"<.*?>", s))   # ['<b>', '</b>', '<i>', '</i>']
print(re.findall(r"<[^>]*>", s)) # ['<b>', '</b>', '<i>', '</i>']

Первый шаблон захватил всю строку от первой < до последней >. Знак ?
после квантификатора делает его ленивым — берётся минимум. Третий вариант,
через отрицающий набор, работает быстрее ленивого и обычно предпочтительнее.

Вторая мина рядом: findall при наличии групп возвращает не сами совпадения,
а содержимое групп.

print(re.findall(r"(\d)(\d)", "12 34"))   # [('1', '2'), ('3', '4')]
print(re.findall(r"(?:\d)(\d)", "12 34")) # ['2', '4']

Если группа нужна только для скобок, делай её незахватывающей — (?:...).

Замена, разбиение, флаги#

print(re.sub(r"\s+", " ", "много   пробелов\tи\nпереносов"))
  # много пробелов и переносов
print(re.sub(r"(\d{2})\.(\d{2})\.(\d{4})", r"\3-\2-\1", "21.09.2026"))
  # 2026-09-21
print(re.split(r"[;,]\s*", "а, б; в"))   # ['а', 'б', 'в']
print(re.findall(r"^\w+", "раз\nдва", re.MULTILINE))   # ['раз', 'два']
print(re.findall(r"кот", "Кот и кот", re.IGNORECASE))  # ['Кот', 'кот']

В замене \1, \2 ссылаются на группы — строку замены тоже пишут с r.
Флаг re.MULTILINE заставляет ^ и $ срабатывать на каждой строке,
re.IGNORECASE отключает регистр, re.DOTALL разрешает точке совпадать с
переводом строки.

Если один шаблон применяется в цикле, скомпилируй его один раз:
pattern = re.compile(r"\d+"), дальше pattern.findall(text).

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

Обращение к None. re.search(...).group() падает с
AttributeError: 'NoneType' object has no attribute 'group', когда совпадения
нет. Всегда проверяй: m = re.search(...), затем if m:. Подробнее об
аккуратной обработке — в статье про
исключения.

Забытый r. Без него "\b" — это символ забоя, а не граница слова, и
шаблон молча перестаёт находить.

Неэкранированная точка. \d+.\d+ совпадёт с 12x34, потому что точка —
любой символ. Для буквальной точки пишут \., а для экранирования целой
подстроки есть re.escape.

Практика: напиши шаблон, который достаёт из текста все адреса вида
слово@слово.домен, и второй — который заменяет два и больше пробелов подряд
одним. Проверь оба на строке, где заведомо есть и подходящие, и похожие, но
неподходящие куски.

План по этапам

  1. Поиск цифрНайти в строке первое число через re.search и все числа через re.findall.
  2. Сравнить search и matchПрименить обе функции к строке, где совпадение не в начале, и объяснить None.
  3. Достать группыРазобрать дату шаблоном с тремя группами и вывести день, месяц, год по отдельности.
  4. Жадность против лениПрогнать <.*> и <.*?> на одной строке с тегами и записать разницу.
  5. Замена с обратными ссылкамиПереставить части даты через re.sub с \1 и \3.

Начать изучать эту тему у себя

План ляжет в твой репозиторий: отмечай этапы, веди конспект — история изменений покажет, как ты продвинулся.

Начать план

Проверь себя

1.Сколько элементов вернёт re.findall(r"\d+", "заказ 1207 от 21.09.2026")?

2.Что вернёт re.match(r"\d+", "заказ 1207")?

3.Что найдёт re.findall(r"<.*>", "<b>x</b>") — сколько элементов в списке?

4.Какой квантификатор делает поиск ленивым — минимально возможным?

Источники

Было полезно?

Ещё темы

Программирование и IT Регулярные выражения Регулярное выражение — это компактное описание множества строк. Один и тот же синтаксис работает в grep, в редакторе кода, в JavaScript, PHP, Java и Python, поэтому выучить его достаточно один раз. Здесь разобран сам язык шаблонов, а не библиотека конкретного языка. Программирование и IT Python: генераторы Генератор выдаёт значения по одному и только тогда, когда их просят. Он не хранит всю последовательность в памяти, поэтому подходит для больших файлов и бесконечных потоков. Плата за это — генератор одноразовый: пройти по нему дважды не получится. Программирование и IT Как изучить Python с нуля Python хорош для первого знакомства с программированием: код читается почти как текст, а стандартная библиотека закрывает большинство бытовых задач. Этот план ведёт от установки интерпретатора до собственных скриптов, покрытых тестами, — примерно за четыре месяца при занятиях около часа в день. Программирование и IT Python: задачи с решениями Подборка задач по возрастанию сложности — от разворота строки до генератора и декоратора-счётчика. Сначала решай сам и только потом открывай разбор: сравнение своего кода с чужим даёт больше, чем чтение готового. Все решения проверены на Python 3. Программирование и IT Python: срезы Срез вырезает из последовательности кусок по правилу «с какого индекса, до какого, с каким шагом». Запись компактная, но у неё два места, где почти все ошибаются: правая граница не включается, а при отрицательном шаге границы меняются местами. Разберём оба. Программирование и IT Python: декораторы Декоратор — это функция, которая принимает другую функцию и возвращает новую, с добавленным поведением. Знак `@` перед определением — просто короткая запись присваивания. Если держать это в голове, вся тема разбирается за один вечер.

Ещё сценарии