Поиск совпадающих строк с Python и Regex. Часть 1
Возможно, вы знакомы с поиском текста, нажимая CTRL-F и вводя искомые слова. Регулярные выражения идут еще дальше: они позволяют указать образец текста для поиска. Вы можете не знать точный номер телефона компании, но если вы живете в Соединенных Штатах или Канаде, вы знаете, что это будут три цифры, за которыми следует дефис, а затем еще четыре цифры (и, при желании, трехзначный код города на начало). Вот как вы, как человек, узнаете номер телефона, когда видите его: 415-555-1234 - это номер телефона, а 4,155,551,234 - нет.
Мы также ежедневно распознаем всевозможные другие текстовые шаблоны: адреса электронной почты имеют символы @ в середине, номера социального страхования США состоят из девяти цифр и двух дефисов, URL-адреса веб-сайтов часто имеют точку и косую черту, в заголовках новостей используется регистр заголовка, хэштеги в социальных сетях начинаются с символа # и не содержат пробелов и т. д.
В этой статье мы начнем с написания программы для поиска текстовых шаблонов без использования регулярных выражений, а затем узнаем, как использовать регулярные выражения, чтобы сделать код намного менее раздутым.
Поиск шаблонов текста без регулярных выражений.
Допустим, вы хотите найти в строке американский номер телефона. Если вы американец, то вы знаете схему: три числа, дефис, три числа, дефис и четыре числа. Вот пример: 415-555-4242.
Давайте воспользуемся функцией isPhoNumber(), чтобы проверить, соответствует ли строка этому шаблону, вернув True или False. Откройте новую вкладку редактора файлов и введите следующий код; затем сохраните файл как isPhoNumber.py:
def isPhoNumber(phon):
if len(phon) != 12:
return False
for i in range(0, 3):
if not phon[i].isdecimal():
return False
if phon[3] != '-':
return False
for i in range(4, 7):
if not phon[i].isdecimal():
return False
if phon[7] != '-':
return False
for i in range(8, 12):
if not phon[i].isdecimal():
return False
return True
print('Is 415-555-4242 a phone number?')
print(isPhoNumber('415-555-4242'))
print('Is Mike a phone number?')
print(isPhoNumber('Is Mike'))
Результат:
Is 415-555-4242 a phone number?
True
Is Mike a phone number?
False
Функция isPhoNumber() имеет код, который выполняет несколько проверок, чтобы узнать, является ли строка в тексте допустимым номером телефона. Если какая-либо из этих проверок не удалась, функция вернет False. Сначала код проверяет, что строка состоит ровно из 12 символов. Затем он проверяет, что код города (то есть первые три символа в тексте) состоит только из цифровых символов. Остальная часть функции проверяет, соответствует ли строка шаблону телефонного номера: номер должен иметь первый дефис после кода зоны, еще три цифровых символа, затем еще один дефис и, наконец, еще четыре цифры . Если выполнение программы удается пройти все проверки, возвращается True.
Если вы хотите найти номер телефона в более крупной строке, вам придется добавить еще больше кода, чтобы найти шаблон номера телефона. Замените четыре последних вызова функции print() в isPhoNumber.py следующими:
message = 'Перезвоните на номер 415-555-1011. 415-555-9999 мой офисный номер.'
for i in range(len(message)):
chunk = message[i:i+12]
if isPhoneNumber(chunk):
print('Найден номер телефона: ' + chunk)
print('Готово')
Когда эта программа будет запущена, результат будет выглядеть так:
Найден номер телефона: 415-555-1011
Найден номер телефона: 415-555-9999
Готово
На каждой итерации цикла for новый фрагмент из 12 символов из сообщения присваивается переменной chunk.
Хотя в этом примере строка в сообщении короткая, она может состоять из миллионов символов, и программа все равно будет работать менее чем за секунду. Аналогичная программа, которая находит телефонные номера с помощью регулярных выражений, также будет работать менее чем за секунду, но регулярные выражения позволяют быстрее писать эти программы.
Поиск шаблонов текста с помощью регулярных выражений
Предыдущая программа поиска телефонных номеров работает, но в ней используется много кода для выполнения чего-то ограниченного: функция isPhoNumber() состоит из 17 строк, но может найти только один шаблон телефонных номеров. Как насчет номера телефона в формате 415.555.4242 или (415) 555-4242? Что, если бы у номера телефона был добавочный номер, например 415-555-4242 x99? Функция isPhoNumber() не сможет их проверить. Вы можете добавить еще больше кода для этих дополнительных шаблонов, но есть более простой способ.
Регулярные выражения, для краткости именуемые regex, представляют собой описания шаблона текста. Например, \d в регулярном выражении обозначает цифровой символ, то есть любую отдельную цифру от 0 до 9. Регулярное выражение \ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d используется Python для сопоставления с тем же текстовым шаблоном, что и предыдущая функция isPhoNumber(): строка из трех чисел, дефис, еще три числа, еще один дефис и четыре числа. Любая другая строка не будет соответствовать регулярному выражению \ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d.
Но регулярные выражения могут быть намного сложнее. Например, добавление 3 в фигурных скобках ({3}) после шаблона - все равно что сказать: «Сопоставьте этот шаблон три раза». Таким образом, несколько более короткое регулярное выражение \ d {3} - \ d {3} - \ d {4} также соответствует правильному формату номера телефона.
Создание объектов Regex
Все функции регулярных выражений в Python находятся в модуле re. Введите в интерактивную оболочку следующее, чтобы импортировать этот модуль:
import re
Передача строкового значения, представляющего ваше регулярное выражение, в re.compile() возвращает объект шаблона Regex(или просто объект Regex).
Чтобы создать объект Regex, соответствующий шаблону номера телефона, введите в интерактивную оболочку следующее. (Помните, что \ d означает «цифровой символ», а \ d \ d \ d- \ d \ d \ d- \ d \ d \ d \ d - регулярное выражение для шаблона номера телефона.)
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
Теперь переменная phoneNumRegex содержит объект Regex.
Соответствие объектов Regex.
Метод search() объекта Regex ищет в переданной строке любые совпадения с регулярным выражением. Метод search() вернет None, если шаблон регулярного выражения не найден в строке. Если шаблон найден, метод search() возвращает объект Match, у которого есть метод group(), который вернет фактический совпавший текст из искомой строки. Например, введите в интерактивную оболочку следующее:
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNumRegex.search('My number is 415-555-4242.')
print('Phone number found: ' + mo.group())
Phone number found: 415-555-4242
Имя переменной mo - это просто общее имя, используемое для объектов Match. Этот пример сначала может показаться сложным, но он намного короче, чем предыдущая программа isPhoNumber.py, и делает то же самое.
Здесь мы передаем желаемый шаблон в re.compile() и сохраняем полученный объект Regex в phoneNumRegex. Затем мы вызываем search() в phoneNumRegex и передаем search() строку, которую мы хотим сопоставить во время поиска. Результат поиска сохраняется в переменной mo. В этом примере мы знаем, что наш шаблон будет найден в строке, поэтому мы знаем, что будет возвращен объект Match. Зная, что mo содержит объект Match, а не нулевое значение None, мы можем вызвать group() на mo, чтобы вернуть совпадение. Запись mo.group() внутри нашего вызова функции print() отображает полное совпадение, 415-555-4242.
Заключение
Необходимо всего несколько шагов для использования регулярных выражений в Python, каждый шаг довольно прост.
Импортируем модуль регулярного выражения с помощью import re.
Создаем объект Regex с помощью функции re.compile(). (Не забудьте использовать необработанную строку - r'строка'.)
Передадим строку, которую хотим найти, в метод search() объекта Regex. Это возвращает объект Match.
Вызовем метод group() объекта Match, чтобы вернуть строку фактического сопоставленного текста.
Хотя мы и можем тестировать код в интерактивной оболочке, нам также следует использовать веб-тестеры регулярных выражений, которые могут показать, как именно регулярное выражение соответствует введенному нами фрагменту текста. Один из них находится на здесь.
-
- Михаил Русаков
Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.