Сообщить об ошибке.

Жадный квантификатор против не жадного.

При повторении регулярного выражения при помощи a*, результирующее действие состоит в том, чтобы захватить как можно больше строки для анализа. Программист "стреляет себе в ногу", когда пытается подобрать таким образом пару сбалансированных разделителей, таких как угловые скобки, окружающие HTML тег. Такой шаблон как '<.*>' для сопоставления одного HTML тега не работает из-за жадной природы выражения .*.

>>> s = '<html><head><title>Title</title>'
>>> len(s)
# 32
>>> print(re.match('<.*>', s).span())
# (0, 32)
>>> print(re.match('<.*>', s).group())
# <html><head><title>Title</title>

Регулярному выражению '<.*>' сначала соответствует символ '<' в теге , а затем выражение .* потребляет всю остальную часть строки до конечного > в , что соответствует последнему совпадению и не совсем то, что требуется. Поэтому механизм регулярных выражений должен отслеживать символ за символом, пока не найдет очередное совпадение для символа >.

В этом случае решение заключается в использовании не жадных квантификаторов *?, +?, ??, или {m, n}?, которые соответствуют как можно меньшему количеству захвата текста для анализа. В приведенном ниже примере символ '>' проверяется сразу после первого совпадения '<', и когда это не удается, механизм продвигает символ за раз, повторяя проверку '>' на каждом шаге. Это дает как раз правильный результат:

>>> print(re.match('<.*?>', s).group())
# <html>

Обратите внимание, что синтаксический анализ HTML или XML регулярными выражениями является болезненным. Быстрые шаблоны будут обрабатывать общие случаи, но HTML и XML имеют специальные случаи, которые нарушат очевидное регулярное выражение. Если написать регулярное выражение, которое обрабатывает все возможные случаи, то такие шаблоны будут очень сложными и медленными. Для таких задач используйте специализированные модули для синтаксического анализа HTML или XML.