Именованные и незахватывающие группы
Даём группам понятные имена и учимся группировать без лишнего захвата.
Именованная группа
(?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().- Имена делают паттерн читаемым и устойчивым к перестановке групп.
(?:...)— группировка без захвата; не засоряет результат и не сдвигает номера.