Извлечение данных: email, телефоны, даты
Собираем практичные паттерны для типовых данных и честно обсуждаем их пределы.
Регулярка для «реального» формата — это всегда компромисс между простотой и полнотой; идеального паттерна для email или телефона не существует.
Извлечение email
Для практических задач достаточно простого паттерна: «символы слова и точки, собака, домен, точка, зона»:
import re
text = "Пишите на [email protected] или [email protected] сегодня"
print(re.findall(r"[\w.+-]+@[\w-]+\.[\w.-]+", text))
Вывод:
['[email protected]', '[email protected]']
Класс [\w.+-]+ — имя до собаки (буквы, цифры, точки, плюсы), затем @, домен и зона. Этот паттерн ловит подавляющее большинство реальных адресов. Полная же спецификация email (RFC 5322) чудовищно сложна — гнаться за ней регуляркой не нужно.
Извлечение телефонов
Телефоны пишут по-разному: +7 999 123-45-67, 8(800)555-35-35. Вместо одного «идеального» паттерна часто проще выдрать все цифры и затем нормализовать:
import re
raw = "Звоните: +7 999 123-45-67 или 8(800)555-35-35"
for phone in re.findall(r"[\d()+\- ]{10,}", raw):
digits = re.sub(r"\D", "", phone)
print(digits)
Вывод:
79991234567 88005553535
Сначала [\d()+\- ]{10,} выхватил «телефоноподобные» куски (цифры, скобки, плюс, дефис, пробел длиной от 10), потом re.sub(r"\D", "", ...) убрал всё нецифровое. Чистка после грубого захвата надёжнее одной громоздкой регулярки.
Извлечение дат
Если формат даты фиксирован, паттерн прост и надёжен — например, ISO-дата ГГГГ-ММ-ДД:
import re
log = "Старт 2024-06-14, дедлайн 2024-12-31, релиз 2025-01-15"
print(re.findall(r"\d{4}-\d{2}-\d{2}", log))
Вывод:
['2024-06-14', '2024-12-31', '2025-01-15']
Где проходит предел регулярок
Регулярка проверяет форму, но не смысл. Паттерн \d{4}-\d{2}-\d{2} с радостью примет 2024-13-45 — формально это «4 цифры, дефис, 2 цифры...», хотя 13-го месяца не бывает. Проверку «настоящая ли это дата» делают уже кодом: попыткой datetime.strptime. Правило такое: регуляркой ловите кандидатов по форме, а корректность значения проверяйте обычной логикой.
import re
from datetime import datetime
for s in ["2024-06-14", "2024-13-45"]:
if re.fullmatch(r"\d{4}-\d{2}-\d{2}", s):
try:
datetime.strptime(s, "%Y-%m-%d")
print(s, "— настоящая дата")
except ValueError:
print(s, "— форма верна, но такой даты нет")
Вывод:
2024-06-14 — настоящая дата 2024-13-45 — форма верна, но такой даты нет
Итог
- Для email и телефонов берите простой паттерн «на 99% случаев», не гонитесь за идеалом.
- Телефоны удобно грубо захватить, а потом вычистить через
re.sub(r"\D", "", ...). - Регулярка проверяет форму, но не смысл: корректность значения (реальность даты) проверяйте кодом.