На этом шаге мы рассмотрим использование некоторых функций из модуля re.
Вы хотите отыскать совпадение или провести поиск по определенному шаблону.
Если текст, который вы хотите найти, является простым литералом, в большинстве случаев вам подойдут базовые строковые методы, такие как str.find(), str.endswith(), str.startwith() и другие подобные. Например:
>>> text = 'yeah, but no, but yeah, but no, but yeah' >>> # Точное совпадение >>> text == 'yeah' False >>> # Совпадение по началу или концу >>> text.startswith('yeah') True >>> text.endswith('no') False >>> # Поиск места первого вхождения >>> text.find('no') 10 >>>
Для более сложного поиска совпадений используйте регулярные выражения и модуль re. Чтобы проиллюстрировать базовые механики использования регулярных выражений, предположим, что вы хотите найти даты, определенные цифрами, такие как "11/27/2012". Вот пример того, как вы можете это сделать:
>>> text1 = '11/27/2012' >>> text2 = 'Nov 27, 2012' >>> import re >>> # Простое сопоставление: \d+ означает совпадение одной или более цифр >>> if re.match(r'\d+/\d+/\d+', text1): print('yes') else: print('no') yes >>> if re.match(r'\d+/\d+/\d+', text2): print('yes') else: print('no') no >>>
Если вы собираетесь много раз искать по одному и тому же шаблону, часто окупается предварительная компиляция шаблона регулярного выражения в объект шаблона. Например:
>>> datepat = re.compile(r'\d+/\d+/\d+') >>> if datepat.match(text1): print('yes') else: print('no') yes >>> if datepat.match(text2): print('yes') else: print('no') no >>>
match() всегда пытается найти совпадения в начале строки. Если вы хотите провести поиск по всем случаям соответствия шаблону, используйте метод findall(). Например:
>>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.' >>> datepat.findall(text) ['11/27/2012', '3/13/2013'] >>>
При составлении регулярных выражений часто нужно использовать захватывающие группы, заключая части шаблона в скобки. Например:
>>> datepat = re.compile(r'(\d+)/(\d+)/(\d+)')
>>>
Захватывающие группы нередко упрощают последующую обработку найденного текста, поскольку содержимое каждой группы может быть извлечено отдельно. Например:
>>> m = datepat.match('11/27/2012') >>> m <re.Match object; span=(0, 10), match='11/27/2012'> >>> # Извлекаем содержимое каждой группы >>> m.group(0) '11/27/2012' >>> m.group(1) '11 >>> m.group(2) '27' >>> m.group(3) '2012' >>> m.groups() ('11', '27', '2012') >>> month, day, year = m.groups() >>>
>>> # Найти все совпадения (обратите внимание на >>> # разрезание на кортежи) >>> text = 'Today is 11/27/2012. PyCon starts 3/13/2013.' >>> datepat.findall(text) [('11', '27', '2012'), ('3', '13', '2013')] >>> for month, day, year in datepat.findall(text): print('{}-{}-{}'.format(year, month, day)) 2012-11-27 2013-3-13 >>>
Метод findall() проходит по тексту и находит все совпадения, возвращая их в списке. Если вы хотите искать совпадения итеративно, используйте метод finditer():
>>> for m in datepat.finditer(text): print(m.groups()) ('11', '27', '2012') ('3', '13', '2013') >>>
Вводного курса в теорию регулярных выражений здесь вы не найдете. Однако этот рецепт демонстрирует простейшие примеры использования модуля re для поиска совпадений в тексте. Самые основные приемы - компилирование шаблонов с использованием re.compile() и последующее использование таких методов, как match(), findall() или finditer().
При составлении шаблонов часто нужно использовать "сырые" (raw) строки, такие как r'(+)/(+)/(+)'. Подобные строки оставляют символы обратных слешей необработанными, что может быть полезно в контексте применения регулярных выражений. С другой стороны, вы можете использовать двойные обратные слеши: '(\\d+)/(\\d+)/(\\d+)'.
Учтите, что метод match() проверяет только начало строки. Возможно, что он найдет вещи, которых вы не ожидаете. Например:
>>> m = datepat.match('11/27/2012abcdef') >>> m <re.Match object; span=(0, 10), match='11/27/2012'> >>> m.group() '11/27/2012' >>>
Если вам нужно точное совпадение, убедитесь, что шаблон включает символ завершения ($), как в примере ниже:
>>> datepat = re.compile(r'(\d+)/(\d+)/(\d+)$') >>> datepat.match('11/27/2012abcdef') >>> datepat.match('11/27/2012') <re.Match object; span=(0, 10), match='11/27/2012'> >>>
И последнее: если вы проводите простые операции поиска, вы часто можете пропустить шаг компиляции и использовать функции уровня модуля из модуля re. Например:
>>> re.findall(r'(\d+)/(\d+)/(\d+)', text) [('11', '27', '2012'), ('3', '13', '2013')] >>>
Обратите внимание, что если вы проводите много операций поиска совпадений, часто окупается компилирование шаблона и многократное его использование. Функции уровня модуля поддерживают кеш недавно скомпилированных шаблонов, так что вы не получите огромного выигрыша в производительности, но сэкономите несколько обращений и избежите лишней обработки, используя ваш собственный скомпилированный шаблон.
На следующем шаге мы рассмотрим поиск и замену текста.