Регулярное выражение Python находит все совпадающие совпадения?

101

Я пытаюсь найти каждую 10-значную серию чисел в более крупной серии чисел, используя re в Python 2.6.

Я легко могу найти совпадающие совпадения, но мне нужно каждое совпадение в числовой серии. Например.

в "123456789123456789"

У меня должен получиться следующий список:

[1234567891,2345678912,3456789123,4567891234,5678912345,6789123456,7891234567,8912345678,9123456789]

Я нашел ссылки на «опережающий просмотр», но в примерах, которые я видел, показаны только пары чисел, а не более крупные группы, и я не смог преобразовать их за пределы двух цифр.

брюки
источник
6
Представленные решения не будут работать, если совпадающие совпадения начинаются в одной и той же точке, например, сопоставление «a | ab | abc» и «abcd» вернет только один результат. Есть ли решение для этого, которое не требует многократного вызова match () с отслеживанием границы «конца» вручную?
Vítor De Araújo
@ VítorDeAraújo: перекрывающиеся регулярные выражения, например, (a|ab|abc)обычно могут быть переписаны как неперекрывающиеся с вложенными группами захвата, например (a(b(c)?)?)?, где мы игнорируем все, кроме самой внешней (то есть самой левой) группы захвата при распаковке совпадения; по общему признанию, это немного болезненно и менее разборчиво. Это также будет более производительное регулярное выражение для соответствия.
smci

Ответы:

179

Используйте группу захвата внутри просмотра вперед. Предварительный просмотр захватывает интересующий вас текст, но фактическое совпадение технически представляет собой подстроку нулевой ширины перед просмотром вперед, поэтому совпадения технически не перекрываются:

import re 
s = "123456789123456789"
matches = re.finditer(r'(?=(\d{10}))',s)
results = [int(match.group(1)) for match in matches]
# results: 
# [1234567891,
#  2345678912,
#  3456789123,
#  4567891234,
#  5678912345,
#  6789123456,
#  7891234567,
#  8912345678,
#  9123456789]
механическое_ мясо
источник
2
Мой ответ как минимум в 2 раза быстрее, чем этот. Но это хитрое решение, я его поддерживаю.
eyquem 05
16
Explanation = вместо поиска шаблона (10 цифр), он ищет все, что СЛЕДУЕТ шаблоном. Таким образом, он находит позицию 0 строки, позицию 1 строки и так далее. Затем он берет группу (1) - соответствующий шаблон и составляет их список. Очень круто.
Tal Weiss
10
Я присоединился к StackOverflow, ответил на вопросы и поднял свою репутацию, чтобы проголосовать за этот ответ. Я пока застрял с Python 2.4, поэтому я не могу использовать более продвинутые функции регулярных выражений Python 3, и это как раз та причудливая уловка, которую я искал.
TheSoundDefense 07
2
Не могли бы вы добавить дополнительные пояснения к коду. Согласно Stack Overflow, это не лучший способ просто иметь код в ответе. Это обязательно поможет людям.
Акшай Хазари
1
Это действительно полезно. Спасибо: D
Sreekiran
80

Вы также можете попробовать использовать сторонний regexмодуль (не re), который поддерживает перекрывающиеся совпадения.

>>> import regex as re
>>> s = "123456789123456789"
>>> matches = re.findall(r'\d{10}', s, overlapped=True)
>>> for match in matches: print(match)  # print match
...
1234567891
2345678912
3456789123
4567891234
5678912345
6789123456
7891234567
8912345678
9123456789
Дэвид С
источник
Я получаю:TypeError: findall() got an unexpected keyword argument 'overlapped'
Карстен
@Carsten: сначала вам нужно установить regexмодуль:pip install regex
Дэвид Си,
Это сработало, спасибо. Я бы подумал, что получу сообщение об ошибке импорта, если регулярное выражение не установлено
Карстен
17

Я люблю регулярные выражения, но они здесь не нужны.

Просто

s =  "123456789123456789"

n = 10
li = [ s[i:i+n] for i in xrange(len(s)-n+1) ]
print '\n'.join(li)

результат

1234567891
2345678912
3456789123
4567891234
5678912345
6789123456
7891234567
8912345678
9123456789
Eyquem
источник
10
Регулярные выражения здесь не нужны только потому, что вы применяете специальные знания «в большей серии чисел», поэтому вы уже знаете, что каждая позиция 0 <= i < len(s)-n+1гарантированно будет началом 10-значного совпадения. Также я полагаю, что ваш код можно было бы ускорить, было бы интересно использовать код-гольф для скорости.
smci