15 — Нахождение строк, соответствующих шаблону | Питон и КИЛИ

Нахождение строк, соответствующих шаблону

Содержание

  • Сырые строки r''
  • Метод group()
  • Запоминающие группы
  • Ограничение жадности квантификаторов

Если в регулярном выражениии используются специальные значения с \, то лучше использовать синтаксис для «сырых» (raw) строк. Приведем простой пример использования «сырых» строк: предположим, что нужно написать строку, которая бы содержала два подряд идущих символа: \ и n. Мы уже знаем, что если просто написать '\n', то Python превратит это сочетание в символ переноса строки. Однако, если написать r'\n', то Python не будет производить никаких преобразований внутри этой строки.

Проверим, есть ли числа в строке:

if re.search(r'\d', 'Я родился 30 февраля 1930 года'):
    print(True)

Часто нам не просто нужно узнать, находится ли что-то нас интересующее в строке, но и узнать, что именно нашлось. Но функция re.search возвращает не совсем то, чего бы нам хотелось:

>>> s = 'abc'
>>> r = re.search('a', s)
>>> r
<_sre.SRE_Match object; span=(0, 1), match='a'>

Это такой объект, а нам хотелось бы саму найденную строку.

Чтобы получить найденную строку, существует метод group():

first_match = re.search('кот.', 'Кот пришёл к коту и спросил кота: «Бойкот, котелок или скотч?»')
if first_match:
    first_match.group()    # 'кот '
else:
    print('Nothing found.')

Если нужно найти в строке несколько подстрок, то каждую из них можно выделить с помощью круглых скобок.

>>> s = 'корова молоко'
>>> r = re.search('(.+?оро.+?) (.+?оло.+)', s)
>>> r
<_sre.SRE_Match object; span=(0, 12), match='корова молоко'>
>>> r.group(1)
'корова'
>>> r.group(2)
'молоко'

Ограничение жадности

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

>>> s = 'корова молоко'
>>> r = re.search('(.+?оро.+?) (.+?оло.+)', s)

В строке 'корова молоко' мы хотим выделить всё слово, содержащее оро до пробела после него. Поэтому в шаблоне мы пишем после слова “ограничитель” в виде пробела, подразумевая, что парсер регулярных выражений “дойдёт” до этого пробела и остановится. Но . означает любой символ, в том числе и пробел. Как будет трактоваться такое выражение? Будет ли пробел “захватываться” группой?

По умолчанию квантификаторы (прежде всего, + и *) жадные (greedy). Это значит, что они стремятся “съесть” как можно больше символов, подходящих под шаблон. Если мы ожидаем, что в строке 'Онегин, добрый мой приятель' такой шаблон '^.+ ' (справа от квантификатора ограничитель в виде пробела) захватит только первое слово “Онегин”, то мы ошибаемся:

>>> s = 'Онегин, добрый мой приятель'
>>> r = re.search('^.+ ', s)
>>> print(r.group())
Онегин, добрый мой

Ограничитель действует, но только это не первый, а последний пробел в строке, после “мой” перед “приятель”, а не после “Онегина”, как мы хотели.

Чтобы этот шаблон работал как нужно, необходимо ограничить жадность квантификатора. Это делается с подстановкой после него символа ?. Таким образом, чтобы квантификатор был нежадным, его следует записать так: .+?. Проверим:

>>> s = 'Онегин, добрый мой приятель'
>>> r = re.search('^.+? ', s)
>>> print(r.group())
Онегин,

Домашнее задание

Продолжаем делать задание по регуляркам