Когда тянуться к 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, ca|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 читаемым.