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']
работать, как ожидалось