4 правила работы с регулярными выражениями, о которых незаслуженно забывают
В этой статье речь пойдет о приемах, которые открывают двери в мир парсинга сложных строк, их использование может значительно сократить ваши муки при разборе таких конструкций.
Отмена вывода группы
Создадим демонстрационные строки, подключим библиотеку re и напишем простейшее регулярное выражение:
import re s1 = 'г.Москва, ул. Коштоянца д. 5' s2 = '-Москва, проспект Чайковского 3, д.2' s3 = '<span>текст</span>' re.search(r'(г\.)([А-Яа-яеЁ]+)', s1).groups()
Как мы видим, все, что заключено в круглые скобки включается в итоговый вывод. Но так как эти скобки также используются для группировки выражений, такой поведение не всегда желательно. Если мы хотим отменить вывод следует после открывающейся скобки добавить два следующих символа ":?":
re.search(r'(?:г\.)([А-Яа-яеЁ]+)', s1).groups()
Условный поиск
В регулярных выражениях можно задавать разные конструкции поиска в зависимости от нахождения шаблона. В общем виде это выглядит так:
(?(id или name шаблона)вариант1|вариант2)
Вот пример работы для наших двух строк в зависимости от наличия в них символов "г.":
re.search(r'(г\.)?(?(1)(М)|(-М))', s2).groups() re.search(r'(г\.)?(?(1)(М)|(-М))', s1).groups()
Обратите внимание, если убрать в строке s2 символ "-", то получим ошибку, так как регулярное выражение требует, чтобы при условии отсутствия "г." в строке имелось "-М":
Именование частей
Исключительную пользу при работе со сложными регулярными выражениями представляет именование групп поиска, которое задается после открывающейся скобки символами "?P<имя>". Впоследствии именованные группы можно получить в виде словаря посредством метода groupdict. Перепишем способ поиска по условной конструкции с включением именования:
# naming re.search(r'(?P<g>г\.)?(?(g)(?P<let1>М)|(?P<let2>-М))', s1).groupdict() re.search(r'(?P<g>г\.)?(?(g)(?P<let1>М)|(?P<let2>-М))', s2).groupdict()
Ссылки на поисковые вхождения
На группы вхождения можно ссылаться в последующих частях регулярного выражения, что полезно, например, при поиске в тегах. Для ссылки по id группы используется конструкция "\id", а по имени (?P=name):
re.search(r'<([\w]+)>([А-Яа-яёЁ]+)</\1>', s3).groups() re.search(r'<(?P<tag>[\w]+)>([А-Яа-яёЁ]+)</(?P=tag)>', s3).groups()