Центральный вопрос: «Можно ли написать регулярное выражение, которое улавливает только самую длинную последовательность?» Ответ - «да»:
import re
s = 'AGATC_AGATCAGATC_AGATCAGATCAGATC_AGATC_AGATCAGATC'
m = re.search(r'((?:AGATC)+)(?!.*\1)', s)
print m.group() if m else ''
#=> "AGATCAGATCAGATC"
Regex demo <</sup> ¯ \ (ツ) / ¯ > Python demo
Python Механизм регулярных выражений выполняет следующие операции.
( begin capture group 1
(?:AGATC) match 'AGATC' in a non-capture group
+ execute the non-capture group 1+ times
) end capture group 1
(?! begin a negative lookahead
.* match 0+ characters
\1 match the content of capture group 1
) end the negative lookahead
Для строки s
выше, AGATC
сначала будет сопоставлено, но при отрицательном просмотре вперед будет найдено AGATC
как первая часть AGATCAGATC
, поэтому предварительное сопоставление будет отклонено. Тогда AGATCAGATC
будет сопоставлено, но отрицательный просмотр вперед обнаружит AGATCAGATC
как первую часть AGATCAGATCAGATC
, так что предварительное сопоставление также будет отклонено. Затем AGATCAGATCAGATC
будет сопоставлен и принят, поскольку отрицательный просмотр вперед не найдет это совпадение позже в строке. (re.findall
, в отличие от re.search
, также будет соответствовать AGATCAGATC
в конце строки.)
Если использовалось re.findall
, может быть несколько совпадений после самого длинного (см. Последний тест строка в ссылке на демонстрацию регулярного выражения), но длины совпадений не уменьшаются от первого до последнего. Следовательно, первое совпадение, полученное с использованием re.search
, является самым длинным совпадением.