Регулярные выражения Python с нуля: первый шаблон и модуль re
Первый шаблон, который находит любую дату в тексте, а не одну конкретную: import re, re.search, raw-строки и объект Match — всё, чтобы перестать бояться регулярки.
Редакция Питоники
Перед вами типичная задача: в ворохе текста нужно найти дату. Не конкретную «14.03.2025», а любую: завтра в файле окажется «02.11.2024», послезавтра — «07.09.2025». Двадцать проверок if уже написано, а даты всё не находятся. Для таких задач в Python есть отдельный язык внутри языка — регулярные выражения и модуль re из стандартной библиотеки.
Регулярка описывает форму текста, а не конкретные слова: «две цифры, любой символ, две цифры, любой символ, четыре цифры» — это шаблон даты, и он найдёт и мартовскую, и ноябрьскую. В этом уроке вы запустите первый шаблон, узнаете, зачем шаблоны оборачивают в raw-строки r"", и научитесь читать email-шаблон по кусочкам. Весь код исполняется прямо на странице: модуль re работает в браузерной песочнице по-настоящему, без установки Python.
Что такое регулярное выражение простыми словами?
Регулярное выражение (regular expression, на жаргоне — regex, regexp или просто регулярка) — это строка-образец, которая описывает целый класс текстов. Обычная подстрока «кот» совпадает только с котом. Шаблон «к.т» совпадает уже с котом, китом и даже «кыт» — точка в середине означает «здесь любой символ».
Идея та же, что в файловых масках: *.jpg означает «любое имя, но обязательно jpg». Только словарь у регулярок богаче: есть готовые обозначения для «цифра», «буква или цифра», «пробел», «один или много раз». Из этих кирпичиков собираются шаблоны дат, цен, телефонов и адресов почты.
- валидация форм: email, телефон и индекс проверяются одним шаблоном вместо кучи if;
- парсинг: из HTML, логов и отчётов достают данные без ручного разбора строк;
- чистка данных: заменить все даты и телефоны в выгрузке одной командой;
- анализ текста: посчитать слово во всех его формах сразу;
- Pandas и BeautifulSoup принимают регулярки в своих методах — навык переносится в соседние библиотеки.
Чем регулярки отличаются от строковых методов in и find?
У строк в Python уже есть инструменты поиска: оператор in, методы find и index. Почему бы не ими? Они ищут только точную подстроку. «Найди 14.03.2025» — пожалуйста. «Найди любую дату» — уже нет: метода, который понимает «две цифры», у строк не существует.
text = "Заказ отправлен 14.03.2025, ждите письмо."
# строковые методы видят только буквы и подстроки
print("14.03.2025" in text) # нашли конкретную дату
print(text.find("2025")) # и её позицию
# а теперь дата другая - метод бессилен
text2 = "Заказ отправлен 02.11.2024, ждите письмо."
print("14.03.2025" in text2) # точного вхождения нет
True 22 False
in и find выросли из вопроса «есть ли эта конкретная подстрока?». Когда условие превращается в «какие-то символы, потом цифры, потом ещё что-то», методы заканчиваются — и начинается цикл с проверкой каждого символа вручную. Регулярка закрывает именно этот случай: структура текста описывается одной строкой шаблона, а не десятью if.
Как запустить первый шаблон: import re и re.search?
За регулярки в Python отвечает модуль re. Он входит в стандартную библиотеку, поэтому ничего устанавливать не нужно — достаточно import re. Главная функция поиска — re.search(pattern, text): она ищет шаблон pattern в строке text и возвращает первое совпадение.
import re
text = "Заказ отправлен 14.03.2025, ждите письмо."
m = re.search(r"\d\d.\d\d.\d\d\d\d", text)
print(m)
print(m.group())
<re.Match object; span=(16, 26), match='14.03.2025'> 14.03.2025
Разберём строку с шаблоном. r"" в начале — raw-строка, про неё через минуту. Внутри: \d — одна цифра, значит \d\d — две подряд; точка между группами — «любой символ» (её роль сыграли точки в дате); \d\d\d\d — четыре цифры года. Первый шаблон читается так: «две цифры, любой символ, две цифры, любой символ, четыре цифры».
re.search прошла по строке слева направо и на позиции 16 нашла кусок, подходящий под описание: «14.03.2025». Результат — не строка, а специальный объект Match: в нём и что нашли, и где именно. Метод .group() вытаскивает сам найденный текст.
Зачем шаблонам raw-строки r""?
Python и регулярки имеют собственные представления об обратном слэше. Для Python «\n» — перевод строки, «\t» — табуляция. Для регулярки слэш — сигнал «дальше спецсимвол»: \d — цифра. Когда шаблон пишут в обычной строке, два словаря начинают спорить за одни и те же символы.
import re
# без r"" обратный слэш приходится удваивать
pattern_plain = "\\d\\d.\\d\\d.\\d\\d\\d\\d"
pattern_raw = r"\d\d.\d\d.\d\d\d\d"
print(pattern_plain == pattern_raw) # это одна и та же строка
print(re.search(pattern_raw, "встреча 07.09.2025 в 15:00").group())
True 07.09.2025
В обычной строке каждый служебный слэш пришлось удвоить — представьте телефонный шаблон в таком виде: глазами не прочитать. Raw-строка r"..." говорит Python: «слэши не трогай, передавай как есть». Содержимое у обеих строк одинаковое, это проверил блок выше, но запись с r короче и честнее.
s1 = "раз\nдва" # \n Python заменяет на перевод строки
s2 = r"раз\nдва" # raw-строка: два отдельных символа
print(len(s1)) # перевод строки считается одним символом
print(len(s2)) # здесь \n - слэш и буква n
print(repr(s2))
7 8 'раз\\nдва'
В raw-версии ровно то, что написано: слэш и буква n как два отдельных символа. repr даже показывает слэш удвоенным, чтобы его нельзя было спутать с настоящим переводом строки. Шаблоны в raw-строках не искажаются, поэтому правило простое: любой шаблон — в r"". Единственное исключение — шаблон, заканчивающийся на нечётное число слэшей: raw-строку с ним записать нельзя, придётся удвоить слэш вручную.
Что возвращает re.search: объект Match?
При удаче re.search возвращает объект Match — маленькую папку с данными о совпадении. Самое нужное в ней: .group() — найденный текст, .start() и .end() — границы в исходной строке, .span() — обе границы сразу, кортежем.
import re
text = "Цена: 199 рублей"
m = re.search(r"\d+", text)
print(m.group()) # что нашли
print(m.start()) # где начинается
print(m.end()) # где заканчивается
print(m.span()) # обе границы разом
199 6 9 (6, 9)
Границы отсчитываются в символах исходной строки с нуля: в «Цена: 199 рублей» совпадение «199» занимает символы с 6-го по 9-й, не включая 9-й. Это удобно, когда найденное нужно не только показать, но и вырезать или заменить по месту. Заметьте: в шаблоне впервые мелькнул плюс — «один или больше раз», подробно о нём в уроке про квантификаторы.
Раз границы известны, строку можно разрезать обычными срезами — теми же, что работают со списками. Так регулярка и срезы работают в связке: первая находит координаты, второй достаёт куски.
import re
text = "Приходите 21.09.2026 на открытие"
m = re.search(r"\d\d.\d\d.\d\d\d\d", text)
print(text[:m.start()]) # до даты
print(text[m.start():m.end()]) # сама дата
print(text[m.end():]) # после даты
Приходите 21.09.2026 на открытие
Дата вырезана, а по краям остались хвосты — пробелы в них видны, если присмотреться к выводу. В реальном коде хвосты подчищают методом strip() или сразу строят шаблон так, чтобы он захватывал меньше лишнего.
А если совпадения нет? re.search возвращает None — это не ошибка, а нормальный ответ «ничего не нашёл».
import re
m = re.search(r"\d\d\d", "тут нет чисел")
print(m)
if m is None:
print("Совпадений нет - вызывать m.group() нельзя")
None Совпадений нет - вызывать m.group() нельзя
Как выглядит первая настоящая программа с регуляркой?
Соберём изученное в рабочую задачу: пройдём по списку заметок и вытащим дату из каждой. Там, где строковые методы потребовали бы ручного разбора, регулярка справляется одним search внутри цикла.
import re
notes = [
"встреча 07.09.2025 в 15:00",
"чек от 12/05/2024 не нашли",
"даты нет, только текст",
]
for note in notes:
m = re.search(r"\d\d.\d\d.\d\d\d\d", note)
if m:
print("Дата:", m.group())
else:
print("Дата не найдена")
Дата: 07.09.2025 Дата: 12/05/2024 Дата не найдена
Обратите внимание на вторую заметку: шаблон поймал «12/05/2024», хотя даты обычно пишут через точку. Виновата точка в шаблоне — она означает «любой символ» и с радостью сыграла роль слэша. Иногда это удобно: один шаблон ловит несколько форматов записи. Но чаще нужна точность, и как искать именно точку — тема следующего урока о классах символов.
Как прочитать страшный шаблон по кусочкам: пример с email?
Пора снять страх перед «настоящими» регулярками. Вот шаблон email из боевого кода — не идеальный, но рабочий и встречается везде:
r"^\w+@\w+\.\w+$"
# как его читают:
# ^ - начало строки
# \w+ - буквы, цифры или подчёркивания, один или больше раз
# @ - обычная собака, никакой магии
# \w+ - имя домена до точки
# \. - настоящая точка (экранированная)
# \w+ - домен верхнего уровня: ru, com
# $ - конец строки
Семь кусочков — семь простых слов, и шаблон прочитан. Новых значков здесь два: ^ и $ закрепляют шаблон за началом и концом строки, а плюс означает «один или больше раз»; его подробный разбор — в третьем уроке, все способы поиска собраны в уроке про методы re. Заметьте: точка перед доменом экранирована слэшем. Без экранирования она означала бы «любой символ» и пропускала бы адреса вида user@site-ru, где вместо точки стоит дефис.
Что дальше
Вы сделали главное: запустили первый шаблон, разобрались с raw-строками и объектом Match, прочитали по кусочкам email-шаблон. Дальше тема раскрывается слоями: второй урок — классы символов \d, \w, \s и собственные наборы в квадратных скобках; третий — квантификаторы, которые превращают «две цифры» в «сколько угодно цифр» без копипасты. А когда захочется вытащить из страницы все ссылки, пригодится урок про извлечение данных в BeautifulSoup — там регулярки работают в паре с парсером.
Регулярка описывает форму текста, а не конкретные слова: две цифры, любой символ, две цифры, любой символ, четыре цифры.
Сначала предскажи ответ в голове — это главный навык программиста.
import re
m = re.search(r"\d+", "Заказ 42 готов")
print(m.group(), m.start())
import re
text = "встреча в 09:15"
print(re.search(r"\d\d.\d\d", text).group())
import re
print(re.search(r"\d\d\d", "код 25"))
1. Что вернёт re.search, если совпадений в тексте нет?
2. Какой символ в шаблоне означает «любой символ, кроме перевода строки»?
3. Зачем шаблон записывают в raw-строке r""?
4. Что вернёт m.span() для совпадения «199» в строке «Цена: 199 рублей»?
5. Что напечатает print(re.search(r"\d\d", "код 7б42").group())?
В редакторе — строка с датой посылки. Найдите дату шаблоном «две цифры, любой символ, две цифры, любой символ, четыре цифры» и выведите строку «Дата: ...», где вместо многоточия — найденный текст через m.group().
Что такое регулярные выражения простыми словами?
Это язык описания образцов текста: шаблон «две цифры, любой символ, две цифры» находит любую дату, а не одну конкретную. Вместо циклов и кучи if пишется одна строка с шаблоном, а поиск выполняет модуль re — стандартная часть Python.
Как подключить регулярные выражения в Python?
Никакой установки не нужно: модуль re входит в стандартную библиотеку. Достаточно написать import re в начале файла и вызвать re.search(шаблон, строка). В браузерной песочнице этой страницы модуль уже доступен — код запускается прямо в уроке. Для свободных экспериментов со своими шаблонами есть ](/playground/) — тот же интерпретатор, без привязки к уроку.
Зачем перед шаблоном ставят букву r?
r"" делает строку raw: Python передаёт обратные слэши регулярке как есть, не превращая \n в перевод строки. Без raw-строки шаблон может тихо изменить смысл — и вместо цифры \d регулярка начнёт искать перенос строки. Пишите r перед каждым шаблоном.
Что возвращает re.search, если ничего не нашла?
None. Это не ошибка, а честный ответ «совпадений нет», но вызывать .group() у None нельзя — упадёт с AttributeError. Проверяйте результат условием if m: перед тем, как доставать текст.
Понравился урок? Сошлитесь на него
«Регулярка описывает форму текста, а не конкретные слова: две цифры, любой символ, две цифры, любой символ, четыре цифры.»
Скопируйте готовую ссылку в формате HTML, Markdown или чистый адрес и вставьте в статью на Habr, VC, Telegram-канал или свой блог — так о проекте узнают новые читатели.
Что читать дальше
re · Урок 2
Символы и классы символов в регулярках: \d, \w, \s и свои наборы
Цифры, буквы, пробелы и свои наборы в квадратных скобках: полный словарь символьных классов, точка и её аппетиты, экранирование точки в ценах и датах.
re · Урок 3
Квантификаторы в регулярных выражениях: *, +, ? и {n,m}
Сколько раз повторить символ: ноль, один, много или ровно четыре? Четыре квантификатора, диапазоны повторений и две ловушки, из-за которых регулярка находит пустоту.
re · Урок 6
re.match, re.search, re.findall и re.fullmatch: как выбрать метод
Четыре метода поиска на одной и той же строке дают четыре разных результата. Разбираем, где match останавливается, зачем нужен fullmatch и когда компилировать шаблон.
Похожие уроки по темам
Подобраны автоматически по пересечению тем и ключевых слов.
json · Урок 1
Что такое JSON и зачем он Python: первый json.dumps
Первое превращение словаря в json-строку одной командой: import json, json.dumps и честный взгляд на кракозябры в выводе — всё исполняется прямо на странице.
import jsonjson для начинающих
requests · Урок 1
Библиотека requests Python с нуля: первый GET-запрос
Первый GET-запрос на requests: что улетает по сети, что возвращается и как разобрать ответ на статус, заголовки и тело — механику проверяем прямо в браузере.
requests python с нуляпервый get запрос python
re · Урок 11
Практикум: регулярные выражения для email, телефонов и дат
Собираем шаблоны, которые вы будете писать чаще всего: адреса почты, российские телефоны в трёх форматах и даты — с нормализацией группами и честными оговорками о границах регулярных выражений.
регулярное выражение emailрегулярное выражение телефона