匹配最长的重复序列(不是由重复序列组成)

时间:2017-06-09 19:19:21

标签: regex

考虑字符串

aabaabaabaabaab

显然,此字符串由aab的5个相邻出现组成,因此我希望我的正则表达式匹配aab

详细说明:aabaab不是可接受的输出,因为它是通过重复aab而产生的。但是aab是一个有效的结果,因为它不是由重复的较短字符串构成的。

出于问题的原因,我们假设重复段周围可能有其他文本(例如11aabaabaabaabaab22或甚至xaabaabaabaabaabaa)。因此,无法使用^$锚定正则表达式。

失败的想法#1:(.+?)\1+这会捕获aa而不是预期的aab

失败的想法#2:(.+)\1+这会捕获aabaab

纯正的正则表达式可以做到这一点吗?如果是,是否有可能没有动态宽度的后视?

2 个答案:

答案 0 :(得分:5)

您可以使用两个前瞻,第一个搜索最长的模式,第二个搜索最小的模式。重复的第二图案必须(至少)在相同位置结束或在第一图案重复之后结束。要检查这一点,您必须在第一个前瞻中捕获字符串的结尾,并在第二个前瞻中使用对此捕获的反向引用。

(?=(.+)\1+(.*))(?=(.+?)\3+\2$)\3+

demo

结果在第3组

也:

(?=(.+)\1+(.*))(.+?)\3+(?=\2$)\3*

请注意,这两个正则表达式模式为字符串中的一个位置提供结果。如果你想知道对于所有字符串重复一次的最长子字符串的最短模式是什么,你必须找到所有字符串并选择带代码的最长字符串。您可以使用模式来重叠结果:

(?=(.+)\1+(.*))(?=(.+?)\3+\2$)(?=(\3+))

(使用第4组)

答案 1 :(得分:1)

def largest_pattern(value)
  /(.+)\1+/.match(value).try("[]", 1)
end

def smallest_pattern(value)
  /^(.+?)\1+$/.match(value).try("[]", 1)
end

def largest_distinct_pattern(value)
  val = largest_pattern(value)
  if val
    while(new_val = smallest_pattern(val))
      val = new_val
    end
    val
  else
    nil
  end
end

largest_distinct_pattern("aabaabaabaabaab")
=> "aab"