【问题标题】:Shortest Repeating Sub-String最短重复子串
【发布时间】:2012-01-27 20:56:27
【问题描述】:

我正在寻找一种有效的方法来提取最短的重复子字符串。 例如:

input1 = 'dabcdbcdbcdd'
ouput1 = 'bcd'

input2 = 'cbabababac'
output2 = 'ba'

我将不胜感激任何与该问题相关的答案或信息。

另外,在this post,人们建议我们可以使用像这样的正则表达式

re=^(.*?)\1+$

在字符串中找到最小的重复模式。但是这样的表达式在 Python 中不起作用并且总是返回一个不匹配的结果(我是 Python 新手,也许我错过了什么?)。

---跟进---

这里的标准是寻找长度大于一且总长度最长的最短非重叠模式。

【问题讨论】:

  • “最短”如何?重复次数最少? “abcabc ababab”怎么样? “阿巴”? “dd”在你的第一个字符串?部分匹配使这个定义有点奇怪......
  • 没错。在第一个字符串中,d 应该是正确答案。
  • 是的,我已经在那里添加了标准。而且我认为下面的两个答案已经可以引导我找到最终的解决方案。非常感谢。

标签: python regex string-matching


【解决方案1】:

这种模式的快速修复可能是

(.+?)\1+

您的正则表达式失败,因为它将重复字符串锚定到行的开头和结尾,只允许像 abcabcabc 这样的字符串,但不允许 xabcabcabcx。此外,重复字符串的最小长度应该是 1,而不是 0(或者任何字符串都会匹配),因此 .+? 而不是 .*?

在 Python 中:

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

但请注意,此正则表达式只会找到不重叠的重复匹配项,因此在最后一个示例中,将找不到解决方案 d 尽管这是最短的重复字符串。或者看这个例子:这里找不到abcd,因为第一个abcdabc部分已经在第一场比赛中用完了):

>>> 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

【讨论】:

    【解决方案2】:

    ^ 匹配字符串的开头。在您的示例中,重复的子字符串不是从头开始的。 $ 类似。如果没有^$,模式.*? 总是匹配空字符串。 Demo:

    import re
    
    def srp(s):
        return re.search(r'(.+?)\1+', s).group(1)
    
    print srp('dabcdbcdbcdd') # -> bcd
    print srp('cbabababac')   # -> ba
    

    虽然它没有找到最短的子串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-22
      • 1970-01-01
      • 2016-11-17
      • 2018-08-16
      • 1970-01-01
      • 2012-06-07
      • 2012-10-29
      • 2023-03-17
      相关资源
      最近更新 更多