📌 Больше полезных статей по информатике и программированию вы можете найти у нас на сайте.
📢 Следить за новостями мира информатики, а также общаться, делиться впечатлениями и готовиться к экзаменам лучше вместе, в нашем Telegram-канале.
Это заключительная статья из цикла про регулярные выражения. Здесь мы изучим работу скобочных групп и научимся использовать опережающие и ретроспективные проверки в регулярных выражениях.
Остальные доступны по ссылкам ниже:
Скобочные группы
Скобочные группы в регулярных выражениях в Python используются для группировки частей шаблона и извлечения соответствующих подстрок. Это полезно для применения квантификаторов к части выражения, захвата подстрок для дальнейшего использования и более сложного поиска.
Группы обозначаются круглыми скобками «(…)» и имеют такой же смысл, как в математических выражениях.
Например, шаблону «(\d+)-(\d+)» будут соответствовать подстроки формата «<одна и более цифра>-<одна и более цифра>».
Если в шаблоне есть группирующие скобки, то функцией findall() вместо списка найденных подстрок будет возвращён список кортежей, в каждом из которых будет строка, соответствующая каждой группе.
Также сформированные группы можно вызвать методами group() и groops() match-объекта, например, при использовании функции search():
Скобочные выражения группируют вместе части регулярного выражения, и к каждой группе может быть применен квантификатор. К примеру, составим шаблон для определения телефонного номера вида: «12-34-56». То есть у нас есть группа, где любая цифра повторяется 2 раза, далее идет дефис и снова повторяется эта группа, и так еще один раз.
Можем составить такую программу для извлечения телефонного номера из строки:
Давайте подробней разберем работу с группами на следующем примере. Допустим, нам необходимо найти подстроку формата «<текст> = <число>», которую с обеих сторон может окружать любое количество пробельных символов.
Тогда шаблон будет состоять из следующих частей:
- Символы «\s*» для определения любого количества пробельных символов в начале строки.
- Первая группа «([a-zA-Z]+)», которая определяет 1 и более латинских букв подряд.
- Символ «=».
- Вторая группа «(\d+)», которая определяет 1 и более цифр.
- Символы «\s*» для определения любого количества пробельных символов в конце строки.
Напишем такую программу:
Все захваченные группы и их индексы проиллюстрированы на изображении ниже.
Все предыдущие примеры скобочных групп были с захватом содержимого, то есть когда регулярное выражение с такой группой находит совпадение, оно сохраняет подстроку, соответствующую этой группе, что позволяет извлекать её позднее с помощью методов group() или groups().
Но бывают ситуации, когда все же нужно использовать группу для сбора части регулярного выражения, но вы не заинтересованы в извлечении содержимого группы и не планируете далее работать с методами group() и groups(). В таком случае можно использовать группы без захвата содержимого.
Синтаксис таких групп похож на синтаксис групп с захватом содержимого, отличие лишь в том, что внутри скобок, перед выражением ставятся знаки «?:».
Давайте сравним работу обеих групп. В следующем примере первая группа будет без захвата, а вторая – с захватом содержимого:
То есть при поиске совпадения учитываются как группы с захватом содержимого, так и без. Но извлечь мы можем только группу с захватом содержимого.
Позиционные проверки
Позиционные проверки в регулярных выражениях — это специальные конструкции, которые позволяют проверять положение символов в строке, не захватывая их.
Обычно они используются в ситуациях, когда нужно проверить, что подстрока находится до или после определённого сочетания символов. Причем захватываться будет только строка, без этих проверяемых символов.
Различают опережающие и ретроспективные проверки.
Опережающие проверки
Опережающая проверка (lookahead assertion) позволяет проверить, что за текущим шаблоном следует (или не следует) определённый текст, без включения этого текста в результат.
Опережающие проверки бывают положительными и отрицательными:
- Положительные опережающие проверки «(?=…)»
- Отрицательные опережающие проверки «(?!…)»
Положительные опережающие проверки проверяют, что за текущей позицией в строке следует подстрока, соответствующая шаблону внутри «(?=…)», но не захватывают её в результатах.
Для примера давайте найдём подстроку максимальной длины (выделена зелёным), после которой находятся символы «cba» (выделены оранжевым) в строке «abcabccbabaccab».
В случае с отрицательными опережающими проверками всё наоборот. Они проверяются, что за текущей позицией в строке не следует подстрока, соответствующая шаблону внутри «(?!…)».
Например, выберем все буквы A, после которых не следует буква C:
Ретроспективные проверки
Теперь перейдём к ретроспективным проверкам. Ретроспективная проверка (lookbehind assertion) позволяет проверить, что перед текущим шаблоном находится (или не находится) определённый текст, без включения этого текста в результат.
Так же, как и опережающие, ретроспективные проверки делятся на положительные и отрицательные.
Положительные ретроспективные проверки «(?<=…)» проверяют, что перед текущей позицией в строке существует подстрока, соответствующая шаблону внутри «(?<=…)», но не захватывают её в результатах.
Обратите внимание, что ретроспективные проверки должны иметь фиксированную длину. Шаблоны переменной длины (например, с использованием квантификаторов) в ретроспективных проверках не поддерживаются.
Давайте теперь найдём максимальную подстроку, перед которой находятся символы «cba» во все той же строке: «abcabccbabaccab»
Отрицательные же ретроспективные проверки проверяют, что перед текущей позицией в строке не существует подстрока, соответствующая шаблону внутри «(?<!…)».
Немного усложним наши примеры. У нас есть строка, состоящая из пар символов: «AB AC DC BB CA AD». Нужно вывести вторую букву (выделены зелёным) только тех пар, которые не начинаются с А (выделены оранжевым).
В коде это будет выглядеть так:
Ну и, конечно, проверки можно совмещать друг с другом. Например, в последовательности чисел найдем то, что находится после четного и перед нечётным: