На этом шаге мы рассмотрим использование символа ? при построении регулярных выражений.
Вы пытаетесь найти совпадение по текстовому шаблону, используя регулярное выражение, но оно находит самое длинное из всех возможных совпадений. Вы же хотите найти самое короткое из всех возможных.
Эта проблема часто возникает при использовании шаблонов, которые пытаются найти текст, заключенный в пару открывающих и закрывающих разделителей (например, строку в кавычках). Рассмотрим следующий пример:
>>> str_pat = re.compile(r'\"(.*)\"') >>> text1 = 'Computer says "no."' >>> str_pat.findall(text1) ['no.'] >>> text2 = 'Computer says "no." Phone says "yes."' >>> str_pat.findall(text2) ['no." Phone says "yes.'] >>>
В этом примере шаблон r'\"(.*)\"' пытается найти текст, заключенный в кавычки. Однако оператор * в регулярном выражении является жадным, поэтому поиск получается поиском самого длинного из возможных совпадений. Поэтому во втором примере с переменной text2 неверно выполняется сопоставление двух строк в кавычках.
Чтобы исправить это, добавьте модификатор ? после оператора * в шаблоне:
>>> str_pat = re.compile(r'\"(.*?)\"') >>> str_pat.findall(text2) ['no.', 'yes.'] >>>
Это делает поиск совпадений нежадным и выводит кратчайшее из найденных совпадений.
Этот рецепт решает одну из часто встречающихся при написании регулярных выражений с символом точки (.) задач. В шаблоне точка соответствует любому символу, за исключением символа новой строки. Однако если вы окружите точку открывающим и закрывающим текстом (таким как кавычки), поиск будет пытаться найти самое длинное из возможных совпадений. Это вызывает многочисленные случаи пропуска открывающего и закрывающего текста и включения в результаты самого длинного совпадения. Добавление ? сразу после таких операторов, как * или +, заставляет алгоритм поиска искать самое короткое совпадение.
На следующем шаге мы рассмотрим написание регулярного выражения для многострочных шаблонов.