Python re.findall() работает не так, как ожидалось

у меня есть код:

import re
sequence="aabbaa"
rexp=re.compile("(aa|bb)+")
rexp.findall(sequence)

возвращает ['aa']

если у нас есть

import re
sequence="aabbaa"
rexp=re.compile("(aa|cc)+")
rexp.findall(sequence)

мы ['aa','aa']

почему есть разница и почему (для первого) мы не получаем ['aa','bb','aa']?

спасибо!

4 ответов


позвольте мне объяснить, что вы делаете:

regex = re.compile("(aa|bb)+")

вы создаете регулярное выражение, которое будет искать aa или bb а затем попытается найти, если есть больше aa или bb после этого, и он будет продолжать искать aa или bb пока он не найдет. поскольку вы хотите, чтобы ваша группа захвата возвращала только aa или bb тогда вы получаете только последнюю захваченную / найденную группу.

однако, если у вас есть такая строка:aaxaabbxaa вы получите aa,bb,aa потому что вы сначала смотрите на строку и находите aa, то вы ищете больше, и найти только x, таким образом, у вас есть 1 группа. тогда вы найдете другого aa, но тогда вы найдете bb, а потом x Итак, вы останавливаетесь, и у вас есть вторая группа, которая bb. тогда вы найдете другого aa. и поэтому ваш конечный результат aa,bb,aa

надеюсь, это объясняет, что вы делаете. как и ожидалось. чтобы получить любую группу aa или bb нужно удалить the + который говорит регулярному выражению искать несколько групп перед возвращением соответствия. и просто иметь regex вернуть каждый матч aa или bb...

так что ваше регулярное выражение должно быть:

regex = re.compile("(aa|bb)")

ура.


нежелательное поведение сводится к тому, как вы формулируете регулярное выражение:

rexp=re.compile("(aa|bb)+")

скобки (aa|bb) образует группу.

и если мы посмотрим на документы findall мы увидим это:

возвращает все неперекрывающиеся совпадения шаблона в строке в виде списка веревка. Строка сканируется слева направо, и совпадения возвращаются в ордене нашли. если или более групп присутствует в шаблоне, возвращает список групп; это будет список кортежей, если шаблон имеет более одной группы. Пустые матчи включены в результат если только они не коснутся начала другого матча.**

как вы сформировали группу, он mathced первый aa, потом bb, потом aa снова (из-за + Квантор). Итак, эта группа держит aa в конце. И findall возвращает это значение в списке ['aa'] (так как есть только один матч aabbaa всего выражения, список содержит только один элемент aa, который сохраняется в группе).

из кода, который вы дали, вы, казалось, хотели сделать это:

>>> rexp=re.compile("(?:aa|bb)+")
>>> rexp.findall(sequence)
['aabbaa']

(?: ...) не создает никакой группы, поэтому findall возвращает соответствие всего выражения.

в конце вашего вопроса вы показываете желаемый результат. Это достигается просто глядя на aa или bb. Нет кванторов (+ или *) необходимы. Просто сделайте это так, как в ответе Inbar Rose:

>>> rexp=re.compile("aa|bb")
>>> rexp.findall(sequence)
['aa', 'bb', 'aa']

ваш шаблон

rexp=re.compile("(aa|bb)+")

соответствует всей строке aabbaa. чтобы уточнить, просто посмотрите на это

>>> re.match(re.compile("(aa|bb)+"),"aabbaa").group(0)
'aabbaa'

также никакие другие подстроки не должны совпадать тогда

>>> re.match(re.compile("(aa|bb)+"),"aabbaa").group(1)
'aa'

таким образом, findall вернет только одну подстроку

>>> re.findall(re.compile("(aa|bb)+"),"aabbaa")
['aa']
>>> 

Я не понимаю, почему вы используете + - это означает 0 или 1 раз, и обычно используется, когда вы хотите найти строку с дополнительным включением подстроки.

>>> re.findall(r'(aa|bb)', 'aabbaa')
['aa', 'bb', 'aa']

работать, как ожидалось