Именованные и незахватывающие группы

Даём группам понятные имена и учимся группировать без лишнего захвата.

Именованная группа (?P<имя>...) — захватывающая группа с человекочитаемым именем вместо номера.

Проблема номеров

Обращаться к группам по номерам — group(1), group(2) — удобно, пока групп две-три. В сложном паттерне легко запутаться: какая группа под каким номером? А если добавить группу в начало — все номера сдвинутся. Решение — имена.

Именованные группы (?P<name>...)

В Python именованная группа записывается как (?P<имя>паттерн). Доступ — по имени:

import re

pattern = r"(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})"
m = re.search(pattern, "2024-06-14")
print(m.group("year"))
print(m.group("month"))
print(m.groupdict())

Вывод:

2024
06
{'year': '2024', 'month': '06', 'day': '14'}

Метод groupdict() возвращает словарь «имя — значение». Код становится самодокументируемым: m.group("year") читается куда понятнее, чем m.group(1). Именованные группы по-прежнему доступны и по номеру.

Незахватывающие группы (?:...)

Иногда скобки нужны только для группировки (чтобы повесить квантор или альтернацию), а захватывать содержимое не нужно — оно засоряет результат и сдвигает номера. Тогда используют незахватывающую группу (?:...):

import re

# хотим вытащить только домен, протокол группируем без захвата
m = re.search(r"(?:https?://)(\w+\.\w+)", "https://example.com")
print(m.group(1))

Вывод:

example.com

Протокол (?:https?://) сгруппирован (чтобы ? относился к s), но не захвачен. Поэтому домен оказался в группе 1, а не 2. Без ?: протокол занял бы первый номер и сбил нумерацию.

Когда что выбирать

СинтаксисЗахватывает?Когда
(...)да, по номерунужна часть совпадения
(?P<имя>...)да, по именигрупп много, нужна читаемость
(?:...)нетгруппировка без захвата

Итог

  • (?P<имя>...) — именованная группа; доступ через group("имя") и groupdict().
  • Имена делают паттерн читаемым и устойчивым к перестановке групп.
  • (?:...) — группировка без захвата; не засоряет результат и не сдвигает номера.
Проверьте себя
1. Как в Python записать именованную группу с именем year?
A(year:\d{4})
B(?P<year>\d{4})
C(<year>\d{4})
D{year:\d{4}}
2. Что делает незахватывающая группа (?:...)?
AГруппирует часть паттерна, но не сохраняет её как отдельную группу
BЗахватывает текст, но без имени
CДелает группу необязательной
DИнвертирует совпадение
3. Что вернёт метод groupdict()?
AСписок всех совпадений
BСловарь {имя_группы: совпавший_текст} для именованных групп
CТолько первую группу
DКортеж всех групп по номерам
Поддержать проект