Menu

Регулярные выражения в Python: модуль re, паттерны, группы и замены

Практическое введение в модуль re - поиск, matching, захватывающие группы, замены и паттерны, к которым будешь тянуться чаще всего.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Когда тянуться к regex

Регулярные выражения - маленький язык для описания текстовых паттернов. Они мощные и легко над-используются.

Прежде чем идти к re, спроси себя, справятся ли обычные методы строк. .split(), .replace(), .startswith(), "target" in text - быстрее, читаемее и менее подвержены ошибкам, чем эквивалентный regex. Оставь regex для случаев, где нужный тебе паттерн действительно структурированный, но слишком гибкий для фиксированных строковых операций: email-ы, номера телефонов, лог-строки с известной формой, HTML или Markdown куски, любой поиск «найди такое-то вот».

Базовый словарь

Regex-паттерн - строка, описывающая то, что ты ищешь. Несколько кирпичиков:

  • . - любой один символ
  • \d - любая цифра (0–9)
  • \w - любой «словесный» символ (буква, цифра, подчёркивание)
  • \s - любой пробельный символ
  • ^ - начало строки
  • $ - конец строки
  • [abc] - один из a, b или c
  • [^abc] - любой символ, кроме a, b, c
  • a|b - a или b
  • * - ноль или больше предыдущего
  • + - один или больше
  • ? - ноль или один
  • {3} - ровно 3
  • {2,5} - от 2 до 5
  • ( ... ) - группа (захватывает совпадение внутри)

Этого хватит на большинство реальных regex-ов.

Ключевые функции

re.search(pattern, text) находит первое совпадение где угодно в строке. Возвращает match-объект или None:

Всегда используй raw-строку (r"...") для regex-паттернов. Иначе Python попытается интерпретировать обратные слэши как строковые escape-ы, и ты получишь другой паттерн, чем задумывал.

re.match(pattern, text) как search, но совпадает только в начале:

Чаще всего нужен search.

re.findall(pattern, text) возвращает все неперекрывающиеся совпадения списком:

Заметь: findall возвращает строки, а не match-объекты. Если в паттерне одна группа - получишь содержимое группы. Несколько групп - список кортежей.

Захватывающие группы

Скобки в паттерне захватывают то, что совпало внутри:

Именованные группы обычно читаются лучше:

Как только в regex больше одной группы, имена делают код извлечения значительно понятнее.

Замена через re.sub

re.sub(pattern, replacement, text) заменяет каждое совпадение:

Вырезает всё, что не цифра. В замене можно ссылаться на захваченные группы через \1, \2 и так далее, а в raw-строках \g<1> яснее:

В качестве замены можно передать и функцию. Удобно для преобразований, не сводящихся к простому обмену:

Компилируем паттерн для переиспользования

Если ты используешь один и тот же паттерн много раз - особенно в цикле, - скомпилируй его один раз:

У скомпилированных паттернов те же методы - search, match, findall, sub - только без паттерна первым аргументом. Чуть эффективнее и часто читаемее.

Флаги

Типичные модификаторы, передаваемые аргументом flags= или соединяемые через |:

  • re.IGNORECASE (re.I) - без учёта регистра.
  • re.MULTILINE (re.M) - ^ и $ совпадают на каждой строке, а не только на границах всей строки.
  • re.DOTALL (re.S) - . совпадает и с переводом строки (по умолчанию - нет).
  • re.VERBOSE (re.X) - разрешает пробелы и #-комментарии в паттерне ради читаемости.

re.VERBOSE особенно удобен для сложных паттернов:

Многострочные закомментированные regex-ы поддерживать гораздо проще, чем непрозрачные однострочники.

Жадные vs ленивые

Квантификаторы (*, +, ?, {n,}) по умолчанию жадные - хватают как можно больше. Добавь ?, чтобы сделать их ленивыми:

Жадная версия захватывает всю подстроку от <b> до </i> - скорее всего, не то, чего ты хотел. Ленивый .+? останавливается на первом >.

(Заметка на полях: реальный HTML regex-ом в продакшене не парсят. Используй html.parser или BeautifulSoup. Пример выше - только ради демонстрации жадности.)

Реалистичный пример

Разбор строк простого лога:

Много мощности в немногих строках.

Несколько привычек

  • Всегда используй raw-строки для паттернов.
  • Начинай с простейшего работающего паттерна; ужесточай потом.
  • Именованные группы - как только групп больше одной.
  • Компилируй паттерны, которые будешь переиспользовать.
  • Regex медленнее обычных методов строк. Если .split() справится - бери .split().

Дальше: ошибки и отладка

Это закрывает тур по реальным данным - файлам, JSON, CSV, HTTP, датам и regex. В любой реальной программе рано или поздно всплывает ошибка, и умение хорошо читать трейсбэки Python - самый большой отладочный навык, который можно развить. Последняя глава - про исключения и конкретные ошибки, которые встречаются чаще всего.

Часто задаваемые вопросы

Что такое regex в Python?

Регулярное выражение (regex) - это маленький язык для описания паттернов в тексте. Модуль re в Python позволяет искать паттерны, извлекать куски и заменять совпадения. Для простых строковых операций это перебор - сначала бери методы строк вроде .split() или .replace(), - но для структурированного поиска regex вне конкуренции.

В чём разница между re.match и re.search?

re.match ищет совпадение только в начале строки. re.search сканирует всю строку и находит первое совпадение где угодно. Сомневаешься - бери search: он ближе к человеческой интуиции.

Всегда ли использовать raw-строки для regex-паттернов?

Да. В regex-паттернах часто есть обратные слэши (\d, \s, \b), которые Python в обычных строках трактует как escape-последовательности. Префикс r - r'\d+' - говорит Python брать строку буквально, что оставляет сам regex читаемым.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ