Флаги: IGNORECASE, MULTILINE, DOTALL
Учимся менять поведение всего паттерна одним переключателем-флагом.
Флаг — модификатор, который меняет правила сопоставления для всего паттерна: например, отключает чувствительность к регистру.
Зачем нужны флаги
Иногда стандартное поведение неудобно. Регулярки чувствительны к регистру: cat не найдёт Cat. Якорь ^ по умолчанию означает начало всей строки, а не каждой строки в многострочном тексте. Точка не ловит перевод строки. Всё это переключается флагами — третьим аргументом функций re.
re.IGNORECASE — без учёта регистра
Флаг re.IGNORECASE (коротко re.I) делает поиск регистронезависимым:
import re
text = "Cat CAT cat CaT"
print(re.findall(r"cat", text))
print(re.findall(r"cat", text, re.IGNORECASE))
Вывод:
['cat'] ['Cat', 'CAT', 'cat', 'CaT']
Без флага нашлось одно точное совпадение; с флагом — все четыре написания. Это незаменимо, когда регистр неважен: ключевые слова, email, расширения файлов.
re.MULTILINE — якоря на каждой строке
Якоря ^ (начало) и $ (конец) по умолчанию относятся ко всей строке-тексту целиком. Флаг re.MULTILINE (re.M) заставляет их срабатывать на каждой строке многострочного текста:
import re
text = "one\ntwo\nthree"
print(re.findall(r"^\w+", text))
print(re.findall(r"^\w+", text, re.MULTILINE))
Вывод:
['one'] ['one', 'two', 'three']
Без флага ^\w+ поймал только первое слово (начало всего текста). С re.MULTILINE — слово в начале каждой строки.
re.DOTALL — точка ловит перевод строки
Как мы помним, точка не совпадает с символом перевода строки \n. Флаг re.DOTALL (re.S) снимает это ограничение — теперь точка значит «вообще любой символ, включая перенос»:
import re
text = "начало\nконец"
print(re.search(r"начало.конец", text))
print(re.search(r"начало.конец", text, re.DOTALL).group())
Вывод:
None начало конец
Без флага точка не перешагнула через \n и совпадения не было. С re.DOTALL точка поймала и перевод строки — поэтому шаблон совпал, и в выводе текст занял две строки.
Несколько флагов сразу
Флаги комбинируют оператором |: re.IGNORECASE | re.MULTILINE. А ещё их можно включать прямо внутри паттерна префиксом, например (?i) для регистронезависимости:
import re
print(re.findall(r"(?i)cat", "Cat CAT cat"))
Вывод:
['Cat', 'CAT', 'cat']
Итог
re.IGNORECASE— поиск без учёта регистра.re.MULTILINE—^и$срабатывают на каждой строке.re.DOTALL— точка начинает ловить и перевод строки.- Флаги передают третьим аргументом и комбинируют через
|; есть и встроенные префиксы вроде(?i).