При повторении регулярного выражения при помощи 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.