python-поиск регулярных выражений и findall

мне нужно найти все совпадения в строке для данного регулярного выражения. Я использовал findall() делать это, пока я не наткнулся на случай, когда он не делал то, что я ожидал. Например:

regex = re.compile('(d+,?)+')
s = 'There are 9,000,000 bicycles in Beijing.'

print re.search(regex, s).group(0)
> 9,000,000

print re.findall(regex, s)
> ['000']

в этом случае search() возвращает то, что мне нужно (самый длинный матч), но findall() ведет себя по-разному, хотя документы подразумевают, что это должно быть то же самое:

findall() соответствует всем вхождениям шаблона, а не только первому как search() делает.

  • почему поведение разное?

  • как я могу достичь результата search() С findall() (или что-то еще)?

2 ответов


хорошо, я вижу, что происходит... из документов:

Если в шаблоне присутствует одна или несколько групп, верните список групп; это будет список кортежей, если шаблон имеет более одной группы.

как оказалось, у вас есть группа, " (\d+,?)"... итак, то, что он возвращает, - это последнее появление этой группы, или 000.

одно из решений-окружить все регулярное выражение группой, как это

regex = re.compile('((\d+,?)+)')

затем, он вернется.[('9,000,000', '000')], который представляет собой кортеж, содержащий обе сопоставленные группы. конечно, ты заботишься только о первом.

лично я бы использовал следующее регулярное выражение

regex = re.compile('((\d+,)*\d+)')

чтобы избежать совпадения таких вещей, как "это плохое число 9,123",

правка.

вот способ избежать необходимости окружать выражение скобками или иметь дело с кортежами

s = "..."
regex = re.compile('(\d+,?)+')
it = re.finditer(regex, s)

for match in it:
  print match.group(0)

finditer возвращает итератор, который можно использовать для доступа к все спички найдены. эти объекты совпадают с теми же, что и re.поиск возвращает, поэтому group (0) возвращает ожидаемый результат.


@aleph_null's ответ правильно объясняет, что вызывает вашу проблему, но я думаю, что у меня есть лучшее решение. Используйте это регулярное выражение:

regex = re.compile(r'\d+(?:,\d+)*')

некоторые причины, почему это лучше:

  1. (?:...) - это группа без захвата, поэтому вы получаете только один результат для каждого матча.

  2. \d+(?:,\d+)* является лучшим регулярным выражением, более эффективным и менее вероятным для возврата ложных срабатываний.

  3. вы всегда должны используйте необработанные строки Python для регулярных выражений, если это возможно; вы с меньшей вероятностью будете удивлены escape-последовательностями регулярных выражений (например,\b на граница слова) интерпретируется как строковые литеральные escape-последовательности (например,\b на backspace).