Регулярное выражение Lookahead не может найти одинаковые совпадения - PullRequest
1 голос
/ 19 февраля 2020

Можно ли найти перекрывающиеся совпадения с помощью регулярных выражений при повторном поиске того же шаблона? Я хочу быть в состоянии найти совпадения, которые происходят три раза. Например, babab встречается трижды в babababab:

babab abab

ba babab ab

baba babab

Это моя текущая реализация Python:

import re
matches = re.findall(r'(?=(\w+).*\1).*\1', "babababab")
print(matches)

Моя программа находит только baba вместо babab. Спасибо!

Ответы [ 2 ]

2 голосов
/ 19 февраля 2020

Один трюк, который вы можете использовать здесь, состоит в том, чтобы просто сопоставить ba(?=bab), что потребляет только ba, что позволяет механизму регулярных выражений логически перемещаться вперед только на одно совпадение:

matches = re.findall(r'ba(?=bab)', "babababab")
matches = [i + 'bab' for i in matches]
print(matches)

Это печатает:

['babab', 'babab', 'babab']

Обратите внимание, что я конкатенирую хвост bab к каждому совпадению, что хорошо, потому что мы знаем, что фактическое совпадение логических c было babab.

1 голос
/ 19 февраля 2020

Мы можем обобщить решение для любого регулярного выражения.

Допустим, у нас есть действительное регулярное выражение pattern, в котором вы хотите искать совпадающие совпадения.

Чтобы получить совпадающие совпадения, нам нужно избегать потребления символов в каждом совпадении, полагаясь на механизм выталкивания для оценки регулярного выражения в каждой позиции строки. Это может быть достигнуто путем окружения всего регулярного выражения в прогнозе (?=<pattern>), и мы можем вложить группу захвата, чтобы захватить совпадение (?=(<pattern>)).

Этот метод работает для Python * Двигатель 1011 *, поскольку после того, как он обнаружил пустое совпадение, он просто столкнется и не будет повторно оценивать регулярное выражение в той же позиции, но будет искать непустое совпадение во второй попытке, как и механизм PCRE.

Пример кода:

import re

inp = '10.5.20.52.48.10'
matches = [m[0] if type(m) is tuple else m for m in re.findall(r'(?=(\d+(\.\d+){2}))', inp)]

Вывод:

['10.5.20', '0.5.20', '5.20.52', '20.52.48', '0.52.48', '52.48.10', '2.48.10']

Если исходный pattern не имеет нумерованных обратных ссылок, то мы можем построить перекрывающуюся версию регулярного выражения со строкой конкатенация.

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

Обратите внимание, что этот метод не даст вам совпадающие совпадения, начинающиеся с того же индекса (например, поиск a+ в aaa даст вам 3 совпадения вместо 6 совпадений). Невозможно реализовать совпадение совпадений, начинающееся с того же индекса в большинстве разновидностей / библиотек регулярных выражений, за исключением Perl.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...