sub с функцией и split по регулярке

Делаем замену по произвольной логике и разбиваем строку по сложным разделителям.

Вторым аргументом re.sub может быть функция: её вызывают для каждого совпадения, и она возвращает строку-замену.

Замена-функция

Когда замена зависит от самого совпадения (а не фиксированная строка), вместо текста передают функцию. Она получает объект Match и возвращает строку. Удвоим все числа в тексте:

import re

def double(m):
    return str(int(m.group()) * 2)

print(re.sub(r"\d+", double, "купить 2 по 10 и 3 по 50"))

Вывод:

купить 4 по 20 и 6 по 100

Для каждого числа вызвалась double: она превратила текст в число, умножила и вернула обратно строкой. Так делают вычисляемые замены, которые невозможно описать одной строкой.

Ещё пример: капитализация

Сделаем первую букву каждого слова заглавной — найдём первую букву слова и заменим функцией:

import re

def up(m):
    return m.group().upper()

print(re.sub(r"\b\w", up, "привет дивный новый мир"))

Вывод:

Привет Дивный Новый Мир

Паттерн \b\w ловит первую букву каждого слова (граница слова + один символ-слово), а функция переводит её в верхний регистр.

split — разбиение по шаблону

Метод str.split умеет делить только по фиксированной строке. re.split делит по шаблону — это спасает, когда разделители разные:

import re

print(re.split(r"[,;]\s*", "яблоко, груша; слива,банан"))

Вывод:

['яблоко', 'груша', 'слива', 'банан']

Разделителем выступила «запятая или точка с запятой, за которой могут идти пробелы». Обычный split так не умеет.

split с захватом разделителей

Если разделитель в паттерне взять в группу, re.split сохранит разделители в результате — иногда это нужно:

import re

print(re.split(r"(\d+)", "abc123def456"))

Вывод:

['abc', '123', 'def', '456', '']

Текст разбился по числам, но и сами числа попали в список (последний элемент — пустая строка, т.к. строка кончилась числом).

Итог

  • Вторым аргументом sub может быть функция — для вычисляемых замен.
  • Функция получает Match и возвращает строку-замену.
  • re.split(pattern, text) делит строку по шаблону-разделителю.
  • Группа в паттерне split сохраняет разделители в результате.
Проверьте себя
1. Что получает функция-замена, переданная в re.sub вторым аргументом?
AПросто строку совпадения
BОбъект Match текущего совпадения
CИндекс совпадения
DВесь исходный текст
2. Чем re.split лучше обычного str.split?
AОн быстрее на любых данных
BОн делит по шаблону-регулярке, а не только по фиксированной строке
CОн сохраняет порядок
DНичем, это одно и то же
3. Что произойдёт, если разделитель в re.split взять в захватывающую группу?
AРазделители будут удалены, как обычно
BРазделители тоже попадут в результирующий список
CБудет ошибка
DРезультат не изменится
Поддержать проект