Короткие Повторяющиеся Подстроки

Я ищу эффективный способ извлечь самую короткую повторяющуюся подстроку. Например:

input1 = 'dabcdbcdbcdd'
ouput1 = 'bcd'

input2 = 'cbabababac'
output2 = 'ba'

Я был бы признателен за любой ответ или информацию, связанную с проблемой.

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

re=^(.*?)+$

чтобы найти наименьший повторяющийся шаблон в строке. Но такое выражение не работает в Python и всегда возвращает мне несоответствие (я новичок в Python и может быть, я что-то упустил?).

--- продолжение ---

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

2 ответов


быстрое исправление для этого шаблона может быть

(.+?)+

ваше регулярное выражение не удалось, потому что оно закрепило повторяющуюся строку в начале и конце строки, позволяя только строки, такие как abcabcabc а не xabcabcabcx. Кроме того, минимальная длина повторяющейся строки должна быть 1, а не 0 (или любая строка будет соответствовать), поэтому .+? вместо .*?.

В Python:

>>> import re
>>> r = re.compile(r"(.+?)+")
>>> r.findall("cbabababac")
['ba']
>>> r.findall("dabcdbcdbcdd")
['bcd']

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

>>> r.findall("abcabcdabcd")
['abc']

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

>>> r.findall("abcdabcdabcabc")
['abcd', 'abc']

лучшее решение:

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

(.+?)(?=)

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

>>> r = re.compile(r"(.+?)(?=)")
>>> r.findall("dabcdbcdbcdd")
['bcd', 'bcd', 'd']

поэтому вы должны отсортировать результаты по длине и вернуть самый короткий:

>>> min(r.findall("dabcdbcdbcdd") or [""], key=len)
'd'

на or [""] (спасибо Дж. Ф. Себастьян!) гарантирует, что нет ValueError срабатывает, если нет совпадений вообще.


^ матчи в начале строки. В вашем примере повторяющиеся подстроки не начинаются с самого начала. Похожие на $. Без ^ и $ шаблон .*? всегда соответствует пустой строке. демо:

import re

def srp(s):
    return re.search(r'(.+?)+', s).group(1)

print srp('dabcdbcdbcdd') # -> bcd
print srp('cbabababac')   # -> ba

хотя он не находит самую короткую подстроку.