Регулярные выражения – очень популярная составляющая почти любого языка программирования. Они помогают быстро получать доступ к необходимой информации. В частности, они используются, когда надо обрабатывать текст. В Python по умолчанию предусмотрен специальный модуль re, отвечающий за работу с регулярными выражениями.
Сегодня мы подробно поговорим о том, что это вообще такое, как осуществляется работа с ними и как модуль re поможет.
- Регулярные выражения: введение
- Что такое шаблон в библиотеке Re?
- Получение отдельной информации из разных строк с помощью регулярных выражений
- Поиск совпадений с помощью трех функций
- re.findall()
- re.search() против re.match()
- Замена части текста с помощью библиотеки Re
- Что такое группы регулярных выражений?
- Понятие «жадного» соответствия
- Популярные шаблоны выражений
- Заключение
Регулярные выражения: введение
Какие сферы применения регулярных выражений? Почти все. Например, такие:
- Веб-приложения, которые требуют проверки текста. Типичный пример – онлайн почтовые клиенты.
- Любые другие проекты, связанные с текстами, базами данных и так дальше.
Перед тем, как мы приступим к разбору синтаксиса, следует детальнее разобраться в основных принципах функционирования библиотеки re и вообще, чем вообще она хороша. Приведем также примеры из реальной практики, где опишем механизм их использования. Вы можете создать такой шаблон, подходит именно вам для выполнения самых разнообразных операций с текстом.
Что такое шаблон в библиотеке Re?
С его помощью можно искать информацию самых разных типов, получать сведения, соответствующие им, с целью сделать другие функции более адаптивными. Ну и, естественно, обрабатывать эти данные.
Например, возьмем следующий шаблон: \s+. Он означает любой знак пробела. Если же к нему добавить знак плюса, то это означает, что в шаблон входит более одного пробела. Он даже может соответствовать символам табуляции, которые вызываются с помощью \t+.
Перед тем, как использовать их, необходимо импортировать библиотеку Re. После этого мы используем специальную команду, чтобы осуществить компиляцию шаблона. Это делается в два шага.
>>> import re
>>> regex = re.compile(‘\s+’)
Конкретно этот код осуществляет операцию компиляции шаблона, который может использоваться. например, для поиска пробелов (одного или большего количества).
Получение отдельной информации из разных строк с помощью регулярных выражений
Предположим, у нас есть переменная, содержащая следующие сведения.
>>> text = «»»100 ИНФ Информатика
213 МАТ Математика
156 АНГ Английский»»»
Она содержит три учебных курса. Каждый из них состоит из трех частей – номера, кода и названия. Видим, что интервал между этими словами различный. Что же делать для того, чтобы эту строку разбить на отдельные числа и слова? Есть два метода достижения этой цели:
- Вызывать функцию re.split.
- Применять функцию split для regex.
Приведем вариант использования синтаксиса каждого из методов для нашей переменной.
>>> re.split(‘\s+’, text)
# или
>>> regex.split(text)
Вывод: [‘100’, ‘ИНФ’, ‘Информатика’, ‘213’, ‘МАТ’, ‘Математика’, ‘156’, ‘АНГ’, ‘Английский’]
Пользоваться, в целом, можно обоими методами. Но на деле значительно проще пользоваться регулярным выражением вместо многократного использования функции re.split.
Поиск совпадений с помощью трех функций
Допустим, нам необходимо вытащить из строки исключительно номера. Что нужно сделать для этого?
re.findall()
Приведем вариант использования функции findall(), которая совокупно с регулярными выражениями позволяет извлечь вхождения одного или больше номеров из текстовой переменной.
>>> print(text)
100 ИНФ Информатика
213 МАТ Математика
156 АНГ Английский
>>> regex_num = re.compile(‘\d+’)
>>> regex_num.findall(text)
[‘100’, ‘213’, ‘156’]
Вместе с символом \d мы использовали шаблон, указывающий на абсолютно любое числовое значение, расположенное в переменной или тексте. А поскольку мы туда добавили один +, то это значит, что должно присутствовать хотя бы одно число.
Также можно использовать знак *, чтобы задать условие, что наличие цифры не обязательно, чтобы было обнаружено совпадение.
Но в нашем случае, поскольку мы использовали +, мы извлекли с помощью findall() 1 и больше цифровых обозначений курсов из текста. Таким образом, в нашем случае регулярные выражения выполняют роль настроек для функции.
re.search() против re.match()
Как можно догадаться по названию функций, первая выполняет поиск соответствия в тексте. Вопрос: в чем же отличие от findall? Дело в том, что он возвращает определенный объект, который подпадает под шаблон, а не всю последовательность найденных результатов в виде перечня, как предыдущая функция.
В свою очередь, функция re.match выполняет те же действия. Только отличается синтаксис. Шаблон должен располагаться в начале.
Приведем пример, который это демонстрирует.
>>> # создайте переменную с текстом
>>> text2 = «»»ИНФ Информатика
213 МАТ Математика 156″»»
>>> # скомпилируйте regex и найдите шаблоны
>>> regex_num = re.compile(‘\d+’)
>>> s = regex_num.search(text2)
>>> print(‘Первый индекс: ‘, s.start())
>>> print(‘Последний индекс: ‘, s.end())
>>> print(text2[s.start():s.end()])
Первый индекс: 17
Последний индекс: 20
213
Если же хочется получить аналогичный результат другим путем, можно использовать для поиска объекта соответствия функцию group().
Замена части текста с помощью библиотеки Re
Чтобы заменять текст, используется функция re.sub(). Предположим, у нас список курсов немного изменился. Видим, что после каждого цифрового значения у нас стоит табуляция. Наша задача – соединить всю эту последовательность в одну строку. Для этого надо заменить выражение \s+ на пропуск.
Изначально текст был таким:
# создайте переменную с текстом
>>> text = «»»100 ИНФ \t Информатика
213 МАТ \t Математика
156 АНГ \t Английский»»»
>>> print(text)
100 ИНФ Информатика
213 МАТ Математика
156 АНГ Английский
Чтобы осуществить нужную операцию, мы использовали следующие строки кода.
# заменить один или больше пробелов на 1
>>> regex = re.compile(‘\s+’)
>>> print(regex.sub(‘ ‘, text))
В результате, у нас получилась одна строка.
101 COM Computers 205 MAT Mathematics 189 ENG English
Теперь рассмотрим другую задачу. Перед нами не стоит задача ставить пробелы. Нам гораздо важнее, чтобы все наименования курсов начинались с новой строки. Для этого используется другое выражение, которое добавляет пропуск новой строки в исключение. Что же за выражение такое?
Библиотека Re поддерживает такую функцию, как отрицательное соответствие. Оно отличается от прямого тем, что содержит перед слэшем восклицательный знак. То есть, если нам надо пропустить символ начала новой строки, то надо вместо \n написать !\n.
Получаем следующий код.
# убрать все пробелы кроме символа новой строки
>>> regex = re.compile(‘((?!\n)\s+)’)
>>> print(regex.sub(‘ ‘, text))
100 ИНФ Информатика
213 МАТ Математика
156 АНГ Английский
Что такое группы регулярных выражений?
С помощью групп регулярных выражений мы можем получать нужные объекты в виде отдельных элементов, а не в одну строчку.
Предположим, нам надо получить номер курса, код и имя не в одной строке, а в виде отдельных элементов. Чтобы выполнить поставленную задачу, понадобится написать огромное количество ненужных строк кода.
На самом деле, можно значительно упростить задачу. Можно компилировать шаблон для всех записей и просто указать те данные, которые необходимо получить из скобок.
Получится очень небольшое количество строк.
# создайте группы шаблонов текста курса и извлеките их
>>> course_pattern = ‘([0-9]+)\s*([А-ЯЁ]{3})\s*([а-яА-ЯёЁ]{4,})’
>>> re.findall(course_pattern, text)
[(‘100’, ‘ИНФ’, ‘Информатика’), (‘213’, ‘МАТ’, ‘Математика’), (‘156’, ‘АНГ’, ‘Английский’)]
Понятие «жадного» соответствия
По стандарту, регулярные выражения запрограммированы на то, чтобы извлекать максимальное количество подходящих данных. Причем даже в том случае, если нужно значительно меньше.
Посмотрим на образец кода HTML, где надо достать тэг.
>>> text = «<body>Пример жадного соответствия регулярных выражений</body>»
>>> re.findall(‘<.*>’, text)
[‘<body>Пример жадного соответствия регулярных выражений</body>’]
Вместо извлечения одного лишь тэга, Python получил всю строку. Поэтому его называют жадным.
А что делать, чтобы получить только тэг? В этом случае необходимо воспользоваться «ленивым соответствием». Чтобы задать такое выражение, в конец шаблона добавляется знак вопроса.
Получится такой код и вывод интерпретатора.
>>> re.findall(‘<.*?>’, text)
[‘<body>’, ‘</body>’]
Если же требуется получить исключительно первое попавшееся вхождение, то используется метод search().
re.search(‘<.*?>’, text).group()
‘<body>’
Тогда будет обнаружен только открывающий тэг.
Популярные шаблоны выражений
Приведем таблицу, содержащую наиболее часто используемые шаблоны регулярных выражений.
Заключение
Мы рассмотрели только самые основные методы, позволяющие работать с регулярными выражениями. В любом случае, вы убедились в том, насколько они важны. И здесь нет разницы, нужно ли сделать парсинг всего текста или же отдельных его фрагментов, нужно ли проанализировать пост в социальной сети или же собрать данные, чтобы потом их обрабатывать. Регулярные выражения являются надежным помощником в этом вопросе.
Они позволяют выполнять такие задачи, как:
- Определение формата данных, например, это электронный адрес или номер телефона.
- Получение строки и разбивка ее на несколько небольших строк.
- Осуществлять различные операции с текстом, такие как поиск, извлечение нужной информации или замена части символов.
Регулярные выражения также позволяют выполнять и нетривиальные операции. На первый взгляд, освоить эту науку непросто. Но на практике все стандартизировано, поэтому достаточно один раз разобраться, после чего этим инструментом можно пользоваться не только в Python, но и любом другом языке программирования. Даже в Excel используются регулярные выражения для автоматизации обработки данных. Так что грех не пользоваться этим инструментом.