一个快速的解决方案是:
(.+?)\1+
你的正则表达式失败了,因为它将重复的字符串锚定到行的开头和结尾,只允许像
abcabcabc
这样的字符串,但不允许像
xabcabcabcx
这样的。此外,重复字符串的最小长度应该是1,而不是0(否则任何字符串都将匹配),因此应该使用
.+?
而不是
.*?
。
在Python中:
>>> import re
>>> r = re.compile(r"(.+?)\1+")
>>> r.findall("cbabababac")
['ba']
>>> r.findall("dabcdbcdbcdd")
['bcd']
请注意,这个正则表达式只会找到非重叠的重复匹配项,所以在最后一个例子中,解决方案d
将无法被发现,尽管它是最短的重复字符串。或者看看这个例子:这里它找不到abcd
,因为第一个abcd
的abc
部分已经在第一次匹配中使用了:
>>> r.findall("abcabcdabcd")
['abc']
此外,它可能会返回多个匹配项,因此您需要在第二步中找到最短的一个:
>>> r.findall("abcdabcdabcabc")
['abcd', 'abc']
更好的解决方案:
为了让引擎也能找到重叠的匹配项,请使用
(.+?)(?=\1)
如果某些字符串重复次数足够多,这将会找到它们两次或更多次出现的情况,但肯定可以找到所有可能的重复子串:
>>> r = re.compile(r"(.+?)(?=\1)")
>>> r.findall("dabcdbcdbcdd")
['bcd', 'bcd', 'd']
因此,您应该按长度对结果进行排序并返回最短的结果:
>>> min(r.findall("dabcdbcdbcdd") or [""], key=len)
'd'
or [""]
(感谢 J. F. Sebastian!)确保如果没有匹配时不会触发 ValueError
。
d
应该是正确答案。 - Tim Pietzcker