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+)*')
некоторые причины, почему это лучше:
(?:...)
- это группа без захвата, поэтому вы получаете только один результат для каждого матча.\d+(?:,\d+)*
является лучшим регулярным выражением, более эффективным и менее вероятным для возврата ложных срабатываний.вы всегда должны используйте необработанные строки Python для регулярных выражений, если это возможно; вы с меньшей вероятностью будете удивлены escape-последовательностями регулярных выражений (например,
\b
на граница слова) интерпретируется как строковые литеральные escape-последовательности (например,\b
на backspace).