🐍 Регулярные выражения в Python за 5 минут: теория и практика для новичков и не только
Учимся использовать Regex: немного теории, примеры выражений и 10 практических заданий для отработки навыков.
Что такое Regex
Регулярные выражения (Regex) – это строки, задающие шаблон для поиска определенных фрагментов в тексте. Помимо поиска, с помощью специальных Regex-шаблонов можно манипулировать текстовыми фрагментами – удалять и изменять подстроки частично или полностью.
Регулярные выражения состоят из набора литералов (букв и цифр) и метасимволов и выглядят примерно так: r'(https?://)?(www\.)?youtube\.(com|nl)/watch\?v=([\w-]+)(&.*?)?(?=[^-\w&=%])'
Используя метасимволы, можно создавать сложные шаблоны, содержащие специальные конструкции для работы с определенными последовательностями и группами символов.
Regex-выражения применяют для обработки текстовых данных, в том числе в скриптах для веб-скрапинга. Кроме того, Regex используют в составе OCR-приложений для очистки отсканированного текста.
Regex в Python
Большинство современных языков программирования поддерживают регулярные выражения, однако степень удобства использования Regex в разных языках варьируется. Python предоставляет простые и понятные методы для работы с регулярными выражениями. Все Regex инструменты находятся в модуле re, который входит в стандартный дистрибутив Python – достаточно импортировать его в свой проект:
import re
Для экранирования служебных символов в шаблонах поиска и замены используют два способа – обратный слэш \
и «сырые» строки r''
. Второй метод предпочтительнее – он позволяет избежать нагромождения слэшей в шаблонах.
Основные функции Regex
re.match() – находит вхождение фрагмента в начале строки. Обычный формат использования – re.match(r'шаблон', строка)
:
Этот код вернет None
, несмотря на то, что в строке есть 5 фрагментов «ку». Это происходит потому, что оба фрагмента расположены не в начале строки.
re.search() – находит первое вхождение фрагмента в любом месте и возвращает объект match. Если в строке есть другие фрагменты, соответствующие запросу, re.search их проигнорирует. У re.search есть дополнительные методы:
.span() – возвращает кортеж, содержащий начальную и конечную позиции искомого фрагмента.
.string – вернет строку, переданную в функцию re.search.
.group() – возвращает фрагмент строки, в котором было обнаружено совпадение.
re.findall() – находит все вхождения фрагмента, в любом месте. Функция re.findall() учитывает регистр символов. Чтобы в результат вошли фрагменты с символами в другом регистре, применяют флаг re.IGNORECASE:
re.split() – расщепляет строку по заданному шаблону. Количество расщеплений задается флагом – в этом примере от строки отделяется только первое слово:
re.sub() – заменяет фрагмент в соответствии с шаблоном:
re.compile() – создает объект из регулярного выражения. Применяется, если один и тот же поисковый шаблон используется в коде несколько раз:
Все перечисленные выше примеры предназначены для выполнения самых простых задач по поиску и замене фрагментов текста. Возможности Regex в Python намного шире: шаблоны могут включать условия, учитывать (или игнорировать) группы символов и диапазоны значений. Для создания таких регулярных выражений используют специальные конструкции, состоящие из метасимволов.
Основные метасимволы в Regex
[]
– используется для указания набора или диапазона символов – re.findall(r'[с-я]', "Камер-юнкер юркнул в бункер", re.I)
, re.findall(r'[аж]', "ажиотаж, мандраж, багаж")
.
\
– указывает на начало последовательности (мы рассмотрим их ниже) или экранирует служебные символы.
.
– выбирает любой символ, кроме новой строки \n
.
^
– проверяет, начинается ли строка с определенного символа / слова / набора символов. Например, r'^Привет
' проверит, начинается ли строка с «Привет». Метасимвол ^
в наборе []
имеет другое значение – проверяет, отсутствуют ли в строке определенные символы (подробнее об этом ниже).
$
– проверяет, заканчивается ли строка в соответствии с шаблоном r'До свиданья.$'
.
*
– ноль или больше совпадений с шаблоном r'ко.*аборация'
.
+
– одно и более совпадений r'к.+ператив'
.
?
– ноль или одно совпадение r'ф.?нтастика'
. Кроме того, нейтрализует «жадность» выражений, которые используют .
, *
, +
для выбора любых символов.
{}
– точное число совпадений r'Интерсте.{2}ар'
.
|
– любой из двух вариантов r'уйду|останусь'
.
()
– захватывает группу для дальнейших манипуляций – re.sub(r'(www)', r'\1.', "wwwwear-gear.com")
.
<>
– создает именованную группу – re.search('(?P<группа1>\w+),(?P<группа2>\w+),(?P<группа3>\w+)', 'дом,улица,фонарь')
Последовательности
Знаком слэша \
обозначается специфическая последовательность символов.
\A
– проверяет, начинается ли строка с определенной последовательности символов. Например, re.findall(r"\AДом", txt)
, проверит, начинается ли предложение со слова «Дом».
\b
– возвращает совпадение, если слово начинается или заканчивается нужной последовательностью символов. Выражение re.findall(r".com\b", s)
проверит, есть ли в строке хотя бы одно доменное имя зоны .com.
\B
– возвращает совпадение, если определенные символы есть в строке, но не в начале или не в конце слова – re.findall(r"\Bро", 'розовая от мороза')
, re.findall(r'ин\B', 'синий апельсин')
.
\d
– проверяет, что в строке есть цифры от 0 до 9 – re.findall("\d", 'при пожаре звоните 112').
\D
– удостоверяет, что цифр в строке нет – re.findall("\D", 'цифр нет')
.
\s
– проверяет наличие пробелов в строке – re.findall("\s", "один пробел")
.
\S
– возвращает совпадение, если в строке есть любые символы, кроме пробелов – re.findall("\S", "непустая строка")
.
\w
– проверяет, есть ли в строке «словесные» символы – знак нижнего подчеркивания, цифры и буквы – re.findall(r"\w", "_\\\\")
.
\W
– возвращает совпадение по каждому «несловесному» символу – re.findall("\W", "здесь есть такие символы!")
.
\Z
– проверит, заканчивается ли строка нужной последовательностью символов – re.findall("конец\Z", "это конец")
.
Наборы и диапазоны символов
Наборы и диапазоны в регулярных выражениях заключены в квадратные скобки:
[есн]
– проверит, есть ли в строке любой из указанных символов е
, с
или н
– re.findall("[есн]", "здесь есть несколько символов из набора")
. Наличие любой цифры из набора проверяется так же – [0169]
.
[а-е]
– вернет совпадения по каждому символу из алфавитного диапазона – re.findall("[а-е]", "здесь есть символы из диапазона")
. Таким же образом возвращает совпадения по диапазону цифр – [5-9]
. Чтобы не использовать флаг re.IGNORECASE
, диапазон можно указывать так – [а-еА-Е]
.
[^абвгд]
– проверит наличие в строке символов, кроме указанных в наборе – re.findall("[^абвгд]", "АБВГДейка – детская передача", re.I)
.
[0-5][0-9]
– возвращает совпадения по двузначным цифрам от 00
до 59
– re.findall("[0-5][0-9]", "будильник сработает в 07:45")
.
Флаги в Regex
Функциональность регулярных выражений расширяется за счет флагов:
Краткий синтаксис | Полный синтаксис | Назначение |
re.A | re.ASCII | Возвращает совпадения только по ASCII-символам вместо всей таблицы Unicode. |
re.I | re.IGNORECASE | Игнорирует регистр символов. |
re.M | re.MULTILINE | Используется совместно с метасимволами ^ и $ . В первом случае возвращает совпадения в начале каждой новой строки \n , во втором – в конце \n . |
re.S | re.DOTALL | Заставляет метасимвол . возвращать совпадения по абсолютно всем символам, включая \n . Без этого флага точка . соответствует любому символу, кроме \n . |
re.X | re.VERBOSE | Разрешает комментарии в Regex-выражениях. |
re.L | re.LOCALE | Учитывает региональные настройки при использовании \w , \W , \b , \B ,
\s и \S . Используется только при работе с байтовыми строками, не совместим с re.ASCII. |
Онлайн-конструкторы регулярных выражений
Чем сложнее регулярное выражение, тем труднее его правильно составить и протестировать. В интернете есть немало визуализаторов Regex, которые значительно упрощают эту задачу. Самый удобный ресурс – regex101. Сайт предоставляет справочную и отладочную информацию, позволяет визуально тестировать шаблоны для поиска и замены. Помимо Python, поддерживает PHP, Java, Golang и JavaScript.
Примеры использования регулярных выражений в Python
Задача 1:
Написать регулярное выражение для извлечения из текста всех email-адресов.
Решение:
Задача 2:
Имеется файл transactions.txt, в котором даты указаны в формате MM/DD/YYYY, при этом в некоторых случаях месяц обозначен первыми тремя буквами: NOV, dec, JAN. Нужно привести даты к формату MM-DD-YYYY.
Решение:
Задача 3:
Вводится последовательность строк. Нужно вывести строки, в которых фрагмент «кот» присутствует в качестве подстроки не менее 2 раз.
Решение:
Задача 4:
Дана последовательность строк. Нужно вывести те, в которых «кот» встречается в качестве отдельного слова.
Решение:
Задача 5:
Вывести слова, состоящие из двух одинаковых слогов.
Решение:
Задача 6:
Вводится последовательность строк. В каждой строке нужно поменять местами две первые буквы в каждом слове, состоящем из двух и более букв.
Решение:
Задача 7:
Напишите функцию для валидации мобильного номера в международном формате. Корректным считается представление номера в таком виде:
Решение:
Задача 8:
Напишите программу для парсинга номеров телефонов с тестовой страницы.
Решение:
Задача 9:
Нужно извлечь все имена и фамилии из текста.
Решение:
Задача 10:
Нужно получить URL всех png и jpg изображений, использованных на главной странице proglib.io:
Заключение
Regex в Python – мощный, гибкий, но достаточно сложный инструмент. Регулярные выражения сложно составлять, поддерживать и редактировать. При работе с текстовыми файлами Regex чаще всего можно заменить методами строк, а при парсинге, в большинстве случаев, использование XPath и CSS-селекторов окажется более эффективным.
Материалы по теме
- Регулярные выражения: 5 сервисов для тестирования и отладки
- Практическое введение в регулярные выражения для новичков
- Регулярные выражения: базовое знакомство для новичков