Пошаговое введение в регулярное выражение с использованием Python

Что такое регулярное выражение?

Regex означает регулярное выражение и по сути является простым способом определения шаблона символов. Регулярное выражение в основном используется для идентификации шаблонов, интеллектуального анализа текста или проверки ввода.

Regex отталкивает многих, потому что на первый взгляд это кажется тарабарщиной. Но те, кто умеет им пользоваться, не могут остановиться! Это мощный инструмент, который стоит изучить.

Введение в Regex

Первое, что вам нужно знать о регулярном выражении, это то, что вы можете соответствовать определенному символу или словам.

Предположим, мы хотим знать, содержит ли конкретная строка букву «а» или слово «лот». Мы можем использовать следующий код на Python:

import re
str = "Learning regex can be a lot of fun"
lst = re.findall('a', str)
lst2 = re.findall('lot', str)
print(lst)
print(lst2)

Это возвращает список с тремя совпадениями и список из одного:

['a', 'a', 'a']
['lot']

Сохраняя те же настройки, представьте, что вы хотите искать эти три буквы в любом порядке: a, b и c. Вы можете составить список, используя квадратные скобки:

lst = re.findall('[abc]', str)
lst2 = re.findall('[a-c]', str)
print(lst)
print(lst2)

Это возвращает:

['a', 'c', 'a', 'b', 'a']
['a', 'c', 'a', 'b', 'a']

Давайте посмотрим на другой пример. Допустим, у вас есть большой архив электронных писем, и вы хотите найти все электронные письма, отправленные Шерлоком своему другу доктору Ватсону. Вы знаете, что заголовок каждого файла электронной почты будет выглядеть так:

From: Sherlock Holmes <[email protected]>
Subject: The giberrish looking algorithm
To: Dr Watson <johnhwatson@mysteryemails.com>

Итак, вы хотите найти что-то, содержащее слово От:, за которым следует адрес электронной почты Шерлока, и Кому:, за которым следует адрес электронной почты доктора Ватсона. Используя только основы, которые мы рассмотрели до сих пор, мы можем отсканировать документ один раз на 'From: Sherlock Holmes ‹ [email protected] ›', а затем еще раз на ' Кому: Dr Watson ‹johnhwatson @ mysteryemails.com '.

import re
str = '''
  From: Sherlock Holmes <[email protected]>
  Subject: The giberrish looking algorithm
  To: Dr Watson <[email protected]>'''
lst = re.findall('From: Sherlock Holmes <[email protected]>',str)
lst2= re.findall('To: Dr Watson <[email protected]>',str)
print(lst)
print(lst2)

Вернув это:

['From: Sherlock Holmes <[email protected]>']
['To: Dr Watson <[email protected]>']

Сопоставив обе строки, мы знаем, что это электронное письмо действительно было отправлено Шерлоком доктору Ватсону.

Шпаргалка по регулярным выражениям

Каждый раз, когда мне нужно написать сложное регулярное выражение, первым делом я обращаюсь к следующему списку доктора Чака Северанса:

Python Regular Expression Quick Guide
^        Matches the beginning of a line
$        Matches the end of the line
.        Matches any character
\s       Matches whitespace
\S       Matches any non-whitespace character
*        Repeats a character zero or more times
*?       Repeats a character zero or more times 
         (non-greedy)
+        Repeats a character one or more times
+?       Repeats a character one or more times 
         (non-greedy)
[aeiou]  Matches a single character in the listed set
[^XYZ]   Matches a single character not in the listed set
[a-z0-9] The set of characters can include a range
(        Indicates where string extraction is to start
)        Indicates where string extraction is to end

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

Заполнение пробелов

Следуя нашему предыдущему примеру, мы хотим сделать наш алгоритм сопоставления с образцом более надежным. Мы хотим выполнить поиск по слову «От:», за которым следует адрес электронной почты Шерлока.

Используя приведенную выше шпаргалку, мы можем использовать «. *» для сопоставления любого символа ноль или более раз.

import re
str = '''
  From: Sherlock Holmes <[email protected]>
  Subject: The giberrish looking algorithm
  To: Dr Watson <[email protected]>'''
lst = re.findall('From:.*[email protected]',str)
print(lst)

Что дает это:

['From: Sherlock Holmes <[email protected]']

Многострочный матч

Продолжая предыдущий пример, давайте расширим шаблон соответствия, чтобы он работал на нескольких строках. Мы можем сделать это с помощью функции (M) ULTILINE для регулярного выражения. Здесь стоит подчеркнуть, что эта функция ожидает, что мы определим, где мы ожидаем увидеть новую строку в сопоставлении с шаблоном.

import re
str = '''
  From: Sherlock Holmes <[email protected]>
  Subject: The giberrish looking algorithm
  To: Dr Watson <[email protected]>'''
lst = re.findall('From:.+[email protected].+\n.*\n.*To:.+[email protected]', str,re.M)
print(lst)

Что дает нам это:

['From: Sherlock Holmes <[email protected]>\n\t\tSubject: The giberrish looking algorithm\n\t\tTo: Dr Watson <[email protected]']

Обратите внимание, что иногда мы используем .*, а иногда .+. Разница в том, что .+ предполагает наличие хотя бы одного символа, тогда как .* может работать с нулем или более символами.

Активизация

Представьте, что вы создаете своего рода проверку для поля ввода, где пользователь может ввести любое число, за которым следует буква d, m или y.

Ваш алгоритм регулярного выражения будет выглядеть примерно так:

^[0-9]+[dmy]$

Разложение вышеупомянутого: ^ означает начало совпадения, за которым следует число 0–9. Однако знак + означает, что это должно быть как минимум одно число от 0 до 9, хотя их может быть и больше. Затем за строкой должны следовать d, m или y, которые должны быть в конце из-за $.

Тестирование вышеперечисленного на python:

import re
str = '1d'
str2 = '200y'
str3 = 'y200'
lst = re.findall('^[0-9]+[dmy]$', str)
lst2 = re.findall('^[0-9]+[dmy]$', str2)
lst3 = re.findall('^[0-9]+[dmy]$', str3)
print(lst)
print(lst2)
print(lst3)

Возвращает это:

['1d']
['200y']
[]

Экранирование специальных символов

Когда дело доходит до регулярных выражений, некоторые символы являются особенными. Например, точка, звезда и знак доллара используются для сопоставления. Что произойдет, если вы захотите сопоставить этих персонажей?

В этом случае мы можем использовать обратную косую черту:

import re
str = 'Sentences have dots. How do we escape them?'
lst = re.findall('.', str)
lst1 = re.findall('\.', str)
print(lst)
print(lst1)

В приведенном выше примере используется точка и точка с обратной косой чертой. Как и следовало ожидать, он возвращает два результата. Первый соответствует всем символам, а второй - только точке.

['S', 'e', 'n', 't', 'e', 'n', 'c', 'e', 's', ' ', 'h', 'a', 'v', 'e', ' ', 'd', 'o', 't', 's', '.', ' ', 'H', 'o', 'w', ' ', 'd', 'o', ' ', 'w', 'e', ' ', 'e', 's', 'c', 'a', 'p', 'e', ' ', 't', 'h', 'e', 'm', '?']
['.']

Соответствие точному количеству символов

Представьте, что вы хотите назначить свидание. Вы знаете, какой будет формат: ДД / ММ / ГГГГ. Иногда будут 2-х или 2-х мегапиксельные, иногда всего одно, но всегда 4-х летнее.

import re
str = 'The date is 22/10/2018'
str1 = 'The date is 3/1/2019'
lst = re.findall('[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4}', str)
lst = re.findall('[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4}', str1)
print(lst)
print(lst1)

Что дает следующие результаты:

['22/10/2018']
['3/1/2019']

Извлечение совпадающего шаблона

Не всегда достаточно знать, что вы сопоставляете шаблон. Вам нужна возможность извлекать информацию из матча.

Например, представьте, что вы просматриваете большой набор данных в поисках адресов электронной почты. Если вы воспользуетесь тем, что мы узнали, вы можете найти образец:

  • начиная с буквы, цифры, точки или символа подчеркивания
  • за которым следует хотя бы еще одна буква или цифра
  • за которым может следовать точка или знак подчеркивания
  • затем @
  • затем снова следуйте той же логике, что и до @
  • наконец, найдите точку, за которой следует буква
^[a-zA-Z0-9\.\_]*[a-zA-Z0-9]+[\.\_]*\@[a-zA-Z0-9\.\_]*[a-zA-Z0-9]+[\.\_]*\.[a-zA-z]+

Из приведенного выше совпадения вы хотите извлечь только доменное имя - то есть все, что находится после @. Все, что вам нужно сделать, это заключить в скобки то, что вам нужно:

import re
str = '[email protected]'
lst = re.findall('^[a-zA-Z0-9\.\_]*[a-zA-Z0-9]+[\.\_]*\@([a-zA-Z0-9\.\_]*[a-zA-Z0-9]+[\.\_]*\.[a-zA-z]+)', str)
print(lst)

Возвращение:

['gmail.com']

В итоге

Таким образом, вы можете использовать регулярное выражение для сопоставления строк данных, и его можно использовать по-разному. Python включает пакет регулярных выражений под названием re, который позволяет вам использовать это. Однако, если вы окажетесь на машине Unix, вы можете использовать регулярное выражение вместе с grep, awk или sed. В Windows, если вы хотите получить доступ ко всем этим командам, вы можете использовать такие инструменты, как Cygwin.

Использованная литература: