Ruby 检查字符串是否是未知子字符串的重复

Ruby 检查字符串是否是未知子字符串的重复,ruby,regex,Ruby,Regex,我正在尝试编写一个正则表达式或Ruby方法,它将查找字符串中最长的重复模式。例如: "abcabc" => "abc" "cccc" => "c" "abcd" => "abcd" 2 a<dd>ititious 4 add<itit>ious 4 addi<titi>ous 6 <alfalf>a 6 a<lfalfa> 2 a<ll>ele 4 al<lele> 12 ambi<

我正在尝试编写一个正则表达式或Ruby方法,它将查找字符串中最长的重复模式。例如:

"abcabc"  => "abc"  
"cccc" => "c"
"abcd" => "abcd"
2 a<dd>ititious
4 add<itit>ious
4 addi<titi>ous
6 <alfalf>a
6 a<lfalfa>
2 a<ll>ele
4 al<lele>
12 ambi<lateralatera>lly
12 ambil<ateralateral>ly
2 ambilateralatera<ll>y
6 <assass>inatress
2 a<ss>assinatress
2 assa<ss>inatress
2 assassinatre<ss>
2 Ca<rr>aran
4 Car<rara>n
/(?=(\w+)(\1+))/i

实现这一点的最佳方式是什么?我天真地尝试了
/^(.**$/
,但这不起作用,因为它只匹配完整的字符串。

我知道它不会那么复杂,所以我仔细考虑并找到了解决方案:

def unrepeat(str)
  n = str.size

  newstr = str
  n.times do |i|
     newstr = newstr[-1] + newstr[0..-2]
     if newstr == str
        return i + 1
     end
  end
end

这将返回重复图案的长度。它通过生成字符串的旋转来发现这一点。

我知道它不会那么复杂,所以我仔细考虑并找到了解决方案:

def unrepeat(str)
  n = str.size

  newstr = str
  n.times do |i|
     newstr = newstr[-1] + newstr[0..-2]
     if newstr == str
        return i + 1
     end
  end
end

这将返回重复图案的长度。它通过生成字符串的旋转来发现这一点。

我不敢相信所有这些呆头呆脑的书头都告诉你不能用模式来完成。正如我将要证明的那样,他们不知道他们在谈论什么。相信我,如果我能用模式解一阶丢番图方程-,我能-那么我当然可以做这个简单的一点。事实上,这对于模式来说非常简单,只要您满足于最左边最长的匹配。例如,只需使用:

/(.+)\1+/
如果匹配,则该字符串包含重复的子字符串

带模式的整数分解 这与使用模式匹配对复合整数进行因子分解的策略相同

首先,创建一个字符串,该字符串是整数的一元表示形式。这将是1的
1
,2的
11
,3的
111
,4的
1111
,等等。给出这样的表示,找到最大因子的模式是:

/^(11+)\1+$/   
其中第一个子群是一元数中的最大因子,因此第一个子群的长度是作为正则数的最大因子。(但是,最大的因素可能不是质数。)

同样地

/^(11+?)\1+$/
是一样的,只是它现在找到了最小的因子,当然它保证是素数。我不知道如何在Ruby中模拟Perl的
x
重复操作符,因此下面是一个使用Perl的快速演示:

$ perl -le 'for $n (@ARGV) { printf "%d is composite and its largest factor is %d.\n", $n, length($1) if ("1" x $n) =~ /^(11+)\1+$/ } ' 5 9 15 24 60 243 891
9 is composite and its largest factor is 3.
15 is composite and its largest factor is 5.
24 is composite and its largest factor is 12.
60 is composite and its largest factor is 30.
243 is composite and its largest factor is 81.
891 is composite and its largest factor is 297.

$ perl -le 'for $n (@ARGV) { printf "%d is composite and its smallest factor is %d.\n", $n, length($1) if ("1" x $n) =~ /^(11+?)\1+$/ } ' 5 9 15 24 60 243 891
9 is composite and its smallest factor is 3.
15 is composite and its smallest factor is 3.
24 is composite and its smallest factor is 2.
60 is composite and its smallest factor is 2.
243 is composite and its smallest factor is 3.
891 is composite and its smallest factor is 3.
在字典中查找此类内容的一个好模式是

/(\w+)\1+/i
这样你就可以不敏感地进行反向引用了

翻字典 这是在字典列表中查找此类内容的快速方法:

$ perl -MEnglish -nle 'print "$PREMATCH<$MATCH>$POSTMATCH" while /(\w+)(\1+)/gi' /usr/share/dict/words 
鬼鬼祟祟的样子=>鬼鬼祟祟的样子 但是,它是最左边最长的子字符串。即使在重叠的情况下,你也必须更加狡猾地找出所有这样的子字符串。例如:

"abcabc"  => "abc"  
"cccc" => "c"
"abcd" => "abcd"
2 a<dd>ititious
4 add<itit>ious
4 addi<titi>ous
6 <alfalf>a
6 a<lfalfa>
2 a<ll>ele
4 al<lele>
12 ambi<lateralatera>lly
12 ambil<ateralateral>ly
2 ambilateralatera<ll>y
6 <assass>inatress
2 a<ss>assinatress
2 assa<ss>inatress
2 assassinatre<ss>
2 Ca<rr>aran
4 Car<rara>n
/(?=(\w+)(\1+))/i
这足以让前两组的比赛全部结束。但是,您可能也需要保留赛前和赛后部分,可能如下所示:

/(?=(.*?)(\w+)(\2+)(.*))/i
现在你可以做一个渐进式的匹配,偷偷地前进,找到所有这样的匹配,甚至重叠!我上面给出的列表是使用以下方法生成的:

$ perl -nle 'print length($2 . $3), " $`.$1<$2$3>$4" while /(?=(.*?)(\w+)(\2+)(.*))/gi' /usr/share/dict/words | perl -pe 's/\.//g' | uniq
和奇迹中的奇迹,它打印出来

One solution is: x=17; y=3; z=2.
与分解复合数一样,您可以使用最小匹配量词更改这些数字的权重。因为第一个
o*
是贪婪的,所以x被允许作为 尽可能大。将一个或多个
*
量词更改为
*?
+
+?
可以产生不同的解决方案:

  ('o' x 281)  =~ /^(o+)\1{11}(o+)\2{14}(o+)\3{15}$/
  # One solution is: x=17; y=3; z=2

  ('o' x 281)  =~ /^(o*?)\1{11}(o*)\2{14}(o*)\3{15}$/
  # One solution is: x=0; y=7; z=11.

  ('o' x 281)  =~ /^(o+?)\1{11}(o*)\2{14}(o*)\3{15}$/
  # One solution is: x=1; y=3; z=14.
这难道不是难以置信吗?但这是真的。自己运行代码,您将看到

是的,如果有人有déjálu,你是对的,你确实读过这一切——因为我早在很久以前就在Perl烹饪书中写过了。这一切仍然适用

注:贝尔实验室的道格拉斯(M.Douglas)首次展示了这一奇迹,这项技术的成功必须归功于他


我真不敢相信所有这些书呆子都告诉你这不能用模式来完成。正如我将要证明的那样,他们不知道他们在谈论什么。相信我,如果我能用模式解一阶丢番图方程-,我能-那么我当然可以做这个简单的一点。事实上,这对于模式来说非常简单,只要您满足于最左边最长的匹配。例如,只需使用:

/(.+)\1+/
如果匹配,则该字符串包含重复的子字符串

带模式的整数分解 这与使用模式匹配对复合整数进行因子分解的策略相同

首先,创建一个字符串,该字符串是整数的一元表示形式。这将是1的
1
,2的
11
,3的
111
,4的
1111
,等等。给出这样的表示,找到最大因子的模式是:

/^(11+)\1+$/   
其中第一个子群是一元数中的最大因子,因此第一个子群的长度是作为正则数的最大因子。(但是,最大的因素可能不是质数。)

同样地

/^(11+?)\1+$/
是一样的,只是它现在找到了最小的因子,当然它保证是素数。我不知道如何在Ruby中模拟Perl的
x
重复操作符,因此下面是一个使用Perl的快速演示:

$ perl -le 'for $n (@ARGV) { printf "%d is composite and its largest factor is %d.\n", $n, length($1) if ("1" x $n) =~ /^(11+)\1+$/ } ' 5 9 15 24 60 243 891
9 is composite and its largest factor is 3.
15 is composite and its largest factor is 5.
24 is composite and its largest factor is 12.
60 is composite and its largest factor is 30.
243 is composite and its largest factor is 81.
891 is composite and its largest factor is 297.

$ perl -le 'for $n (@ARGV) { printf "%d is composite and its smallest factor is %d.\n", $n, length($1) if ("1" x $n) =~ /^(11+?)\1+$/ } ' 5 9 15 24 60 243 891
9 is composite and its smallest factor is 3.
15 is composite and its smallest factor is 3.
24 is composite and its smallest factor is 2.
60 is composite and its smallest factor is 2.
243 is composite and its smallest factor is 3.
891 is composite and its smallest factor is 3.
在字典中查找此类内容的一个好模式是

/(\w+)\1+/i
这样你就可以不敏感地进行反向引用了

翻字典 这是在字典列表中查找此类内容的快速方法:

$ perl -MEnglish -nle 'print "$PREMATCH<$MATCH>$POSTMATCH" while /(\w+)(\1+)/gi' /usr/share/dict/words 
鬼鬼祟祟的样子=>鬼鬼祟祟的样子 但是,它是最左边最长的子字符串。即使在重叠的情况下,你也必须更加狡猾地找出所有这样的子字符串。例如:

"abcabc"  => "abc"  
"cccc" => "c"
"abcd" => "abcd"
2 a<dd>ititious
4 add<itit>ious
4 addi<titi>ous
6 <alfalf>a
6 a<lfalfa>
2 a<ll>ele
4 al<lele>
12 ambi<lateralatera>lly
12 ambil<ateralateral>ly
2 ambilateralatera<ll>y
6 <assass>inatress
2 a<ss>assinatress
2 assa<ss>inatress
2 assassinatre<ss>
2 Ca<rr>aran
4 Car<rara>n
/(?=(\w+)(\1+))/i
这足以让前两组的比赛全部结束。但是,您可能也需要保留赛前和赛后部分,可能如下所示:

/(?=(.*?)(\w+)(\2+)(.*))/i
现在你可以做一个渐进式的匹配,偷偷地前进,找到所有这样的匹配,甚至重叠!我上面给出的列表是使用以下方法生成的:

$ perl -nle 'print length($2 . $3), " $`.$1<$2$3>$4" while /(?=(.*?)(\w+)(\2+)(.*))/gi' /usr/share/dict/words | perl -pe 's/\.//g' | uniq
和奇迹中的奇迹,它打印出来

One solution is: x=17; y=3; z=2.
与分解复合数一样,您可以更改ho