Нахождение строк, соответствующих шаблону
Содержание
- Сырые строки
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())
Онегин,