Урок 5 из 8 · 25 мин · обновлено
Текст и даты: поиск, замена, регулярные выражения
Как приводить текст в порядок на Python: методы строк, регулярные выражения для телефонов, почты и номеров документов, работа с датами через datetime — разбор, формат, сроки и правильная сортировка.
Методы строк
Многие задачи с текстом решаются без сложных инструментов — встроенными методами строк:
name = " Ручка ГЕЛЕВАЯ "
print(name.strip()) # «Ручка ГЕЛЕВАЯ» — без пробелов по краям
print(name.strip().lower()) # «ручка гелевая»
print(name.strip().capitalize()) # «Ручка гелевая»
print("45,50".replace(",", ".")) # «45.50» — теперь можно float()
print("Тетрадь;48 л.;12".split(";")) # ['Тетрадь', '48 л.', '12']
Привести названия товаров к одному виду перед подсчётом — частая задача: иначе «Маркер» и «маркер » окажутся в отчёте двумя разными товарами.
Регулярные выражения
Когда нужно найти в тексте что-то по шаблону — все телефоны, все адреса почты, номер накладной, — используют регулярные выражения. Это маленький язык шаблонов, в Python он живёт в модуле re.
Основные обозначения:
| Шаблон | Что означает |
|---|---|
\d |
любая цифра |
\D |
любой символ, кроме цифры |
\w |
буква, цифра или подчёркивание |
. |
любой символ; сама точка — \. |
+ |
предыдущее — один раз или больше |
{4} |
предыдущее — ровно четыре раза |
[...] |
один из символов в скобках |
(...) |
группа: эту часть совпадения можно достать отдельно |
Три главные функции:
re.findall(шаблон, текст)— найти все совпадения;re.search(шаблон, текст)— найти первое совпадение;re.sub(шаблон, замена, текст)— заменить все совпадения.
Шаблоны пишут в строках с буквой r перед кавычками: r"\d+". Так Python не трогает обратные косые черты.
Приводим в порядок телефоны
Перед рассылкой нужно привести телефоны клиентов к одному виду: +79123456789. В таблице они записаны как попало:
имя;телефон
Ольга;8 (912) 345-67-89
Игорь;+7 912 111 22 33
Анна;9125550011
Пётр;8-912-000
import csv
import re
def normalize_phone(raw):
digits = re.sub(r"\D", "", raw) # оставляем только цифры
if len(digits) == 11 and digits[0] in "78":
digits = digits[1:]
if len(digits) != 10:
return None # номер неполный — пусть проверит человек
return "+7" + digits
with open("клиенты.csv", encoding="utf-8-sig", newline="") as f:
for row in csv.DictReader(f, delimiter=";"):
phone = normalize_phone(row["телефон"])
print(row["имя"], phone or "проверить вручную: " + row["телефон"])
Ольга +79123456789
Игорь +79121112233
Анна +79125550011
Пётр проверить вручную: 8-912-000
Сначала re.sub(r"\D", "", raw) выбрасывает всё, кроме цифр. Потом убираем первую 8 или 7 и проверяем, что осталось ровно 10 цифр. Номер Петра неполный — скрипт его не угадывает, а честно помечает. Это важное правило автоматизации: данные, которые скрипт не понял, должен проверить человек.
Находим почту и номера в тексте
Из письма поставщика нужно достать адреса почты и номера накладных:
import re
text = """Добрый день! Счёт пришлите на buh@kancmarket.ru,
копию — Светлане (svetlana@example.ru). Спасибо!"""
emails = re.findall(r"[\w.-]+@[\w-]+\.[a-z]{2,}", text)
print(emails)
['buh@kancmarket.ru', 'svetlana@example.ru']
Шаблон читается так: несколько букв, цифр, точек или дефисов, затем @, затем имя домена, точка и не меньше двух латинских букв. Он упрощённый — для рабочих задач его обычно хватает.
С группами можно достать только нужную часть совпадения. Например, номера накладных без знака «№»:
text = "Направляем накладные №1406 от 14.10.2026 и №1407 от 16.10.2026."
print(re.findall(r"№(\d+)", text)) # ['1406', '1407']
Даты
Даты в Python — модуль datetime. Две главные операции:
datetime.strptime(текст, шаблон)— разобрать текст в дату;дата.strftime(шаблон)— записать дату текстом.
В шаблоне %d — день, %m — месяц, %Y — год из четырёх цифр. Добавить или отнять дни помогает timedelta:
from datetime import date, datetime, timedelta
delivery = datetime.strptime("28.10.2026", "%d.%m.%Y").date()
payment_due = delivery + timedelta(days=14)
print("Оплатить до:", payment_due.strftime("%d.%m.%Y"))
print("Осталось дней:", (payment_due - date(2026, 10, 30)).days)
Оплатить до: 11.11.2026
Осталось дней: 12
Разница двух дат — тоже timedelta, а .days даёт число дней. В рабочем скрипте вместо date(2026, 10, 30) будет date.today().
Даты в именах файлов
Отчёты лежат в папке с именами «отчёт 5.10.2026.xlsx», «отчёт 12.10.2026.xlsx», «отчёт 28.9.2026.xlsx». Отсортируйте их — и порядок окажется странным:
import re
from datetime import datetime
names = ["отчёт 5.10.2026.xlsx", "отчёт 12.10.2026.xlsx", "отчёт 28.9.2026.xlsx"]
for name in sorted(names):
match = re.search(r"(\d{1,2})\.(\d{1,2})\.(\d{4})", name)
day = datetime(int(match[3]), int(match[2]), int(match[1]))
print(f"{name} → {day:%Y-%m-%d} отчёт.xlsx")
отчёт 12.10.2026.xlsx → 2026-10-12 отчёт.xlsx
отчёт 28.9.2026.xlsx → 2026-09-28 отчёт.xlsx
отчёт 5.10.2026.xlsx → 2026-10-05 отчёт.xlsx
Слева видно, что текст сортируется посимвольно: «1» раньше «2», а «2» раньше «5». Справа те же даты в виде год-месяц-день — в таком виде они сортируются правильно, даже как обычный текст. match[1], match[2], match[3] — группы шаблона: день, месяц, год. Переименовать файлы можно приёмом из урока 2 с пробным запуском.
Попробуйте сами. В письме поставщика: «Направляем накладные №1406 от 14.10.2026 и №1407 от 16.10.2026. Оплата — в течение 14 дней». Найдите все даты и для каждой посчитайте срок оплаты.
Решение
import re
from datetime import datetime, timedelta
text = "Направляем накладные №1406 от 14.10.2026 и №1407 от 16.10.2026. Оплата — в течение 14 дней."
for found in re.findall(r"\d{2}\.\d{2}\.\d{4}", text):
due = datetime.strptime(found, "%d.%m.%Y") + timedelta(days=14)
print(found, "→", f"{due:%d.%m.%Y}")
14.10.2026 → 28.10.2026
16.10.2026 → 30.10.2026
\d{2}\.\d{2}\.\d{4} — две цифры, точка, две цифры, точка, четыре цифры. Точку в шаблоне экранируют \., иначе она означает «любой символ».
Мини-тест · 4 вопроса
Проверьте себя
Выберите вариант, который кажется вам правильным. В конце вы увидите свой результат и объяснение к каждому вопросу.
-
Что вернёт re.sub(r"\D", "", "8 (912) 345-67-89")?
\D — любой символ, кроме цифры. re.sub заменяет все такие символы на пустую строку, остаются только цифры.
-
Как превратить текст «28.10.2026» в дату?
strptime разбирает текст по шаблону: %d — день, %m — месяц, %Y — год из четырёх цифр.
-
Почему файлы «отчёт 12.10.2026», «отчёт 28.9.2026», «отчёт 5.10.2026» сортируются в странном порядке?
Текст сортируется по символам слева направо, а не по смыслу. Даты в виде «2026-10-05» сортируются правильно и как текст.
-
Скрипт нормализации получил номер «8-912-000» и вернул None. Почему так лучше, чем угадывать номер?
Скрипт должен честно сообщать о данных, которые он не понял. Выдуманный номер испортит рассылку, а пометка «проверить вручную» — нет.