Ruby:如何将包含连续字母组的字符串拆分为这些字母组?

Ruby:如何将包含连续字母组的字符串拆分为这些字母组?,ruby,string,Ruby,String,我要转换包含连续字母组的字符串: aaabbcccaaa 进入: [aaa、bbb、ccc、aaa] 我确信这在Ruby中应该是直截了当的,但我被难住了 基因修饰变体 它使用的形式没有块,因此返回枚举数 它使用的形式没有块,因此返回枚举数。此变体应适用于包含两个连续字符组的任何字符串 "foo\n\nbarr".gsub(/(.)(\1)*/).select{|l| l.length >1} #=> ["oo", "rr"] 或仅针对字母字符: "foo\n\n??barr..ba

我要转换包含连续字母组的字符串:

aaabbcccaaa 进入:

[aaa、bbb、ccc、aaa] 我确信这在Ruby中应该是直截了当的,但我被难住了

基因修饰变体

它使用的形式没有块,因此返回枚举数


它使用的形式没有块,因此返回枚举数。

此变体应适用于包含两个连续字符组的任何字符串

"foo\n\nbarr".gsub(/(.)(\1)*/).select{|l| l.length >1}
#=> ["oo", "rr"]
或仅针对字母字符:

"foo\n\n??barr..bazz".gsub(/([a-zA-Z])(\1)*/).select{|l| l.length >1}
#=> ["oo", "rr", "zz"]

此变体应适用于包含两个连续字符组的任何字符串

"foo\n\nbarr".gsub(/(.)(\1)*/).select{|l| l.length >1}
#=> ["oo", "rr"]
或仅针对字母字符:

"foo\n\n??barr..bazz".gsub(/([a-zA-Z])(\1)*/).select{|l| l.length >1}
#=> ["oo", "rr", "zz"]

非正则表达式版本:

str = "aaabbbcccaaa"
str.each_char.with_object([]) { |a,r| (r.last&.end_with?(a) ? r.last : r) << a }
=> ["aaa", "bbb", "ccc", "aaa"]

非正则表达式版本:

str = "aaabbbcccaaa"
str.each_char.with_object([]) { |a,r| (r.last&.end_with?(a) ? r.last : r) << a }
=> ["aaa", "bbb", "ccc", "aaa"]

我找到了一种不用正则表达式使用Arrayslice_的方法,在以下情况下:

AAAABBBCDDD.chars.slice_当&:!=。映射&:join =>[AAAA、BBB、C、DDD] 尽管卡里·斯沃夫兰(Cary Swoveland)在其回答中建议的带正则表达式的gsub显然更快:

Benchmark.measure do
  100_000.times { "AAAABBBCDDD".chars.slice_when(&:!=).map(&:join) }  
end  

# => #<Benchmark::Tms:0x00007fb11ff9a560
#  @cstime=0.0,
#  @cutime=0.0,
#  @label="",
#  @real=1.427345999982208,
#  @stime=0.013876,
#  @total=1.3629069999999996,
#  @utime=1.3490309999999996>

Benchmark.measure do
  100_000.times { "AAAABBBCDDD".gsub(/(.)(\1)*/).to_a }
end

=> #<Benchmark::Tms:0x00007fb1214f4dc0
#  @cstime=0.0,
#  @cutime=0.0,
#  @label="",
#  @real=0.6837240000022575,
#  @stime=0.03575100000000003,
#  @total=0.64306,
#  @utime=0.6073089999999999>

我找到了一种不用正则表达式使用Arrayslice_的方法,在以下情况下:

AAAABBBCDDD.chars.slice_当&:!=。映射&:join =>[AAAA、BBB、C、DDD] 尽管卡里·斯沃夫兰(Cary Swoveland)在其回答中建议的带正则表达式的gsub显然更快:

Benchmark.measure do
  100_000.times { "AAAABBBCDDD".chars.slice_when(&:!=).map(&:join) }  
end  

# => #<Benchmark::Tms:0x00007fb11ff9a560
#  @cstime=0.0,
#  @cutime=0.0,
#  @label="",
#  @real=1.427345999982208,
#  @stime=0.013876,
#  @total=1.3629069999999996,
#  @utime=1.3490309999999996>

Benchmark.measure do
  100_000.times { "AAAABBBCDDD".gsub(/(.)(\1)*/).to_a }
end

=> #<Benchmark::Tms:0x00007fb1214f4dc0
#  @cstime=0.0,
#  @cutime=0.0,
#  @label="",
#  @real=0.6837240000022575,
#  @stime=0.03575100000000003,
#  @total=0.64306,
#  @utime=0.6073089999999999>

@Phrogz在很久以前给出了一个可能适合您的情况的正则表达式。@Phrogz在很久以前给出了一个可能适合您的情况的正则表达式。我理解这里使用的正则表达式是:匹配一个字符,后跟零个或多个完全相同的匹配。但我不明白的是,为什么这在gsub中有效,而在扫描中无效。如果有人能帮我理解原因,我会很感激的。这只是因为他们以一种特殊的方式对待俘虏群体。看医生。清楚了吗?有时,扫描具有该属性是有用的;有时它会妨碍我。我只是注意到我把\1包含在了一个不必要的捕获组中。我不知道这是怎么发生的,也不知道为什么其他人没有指出这一点,但我已经解决了。我理解这里使用的正则表达式是:匹配一个字符,后跟零个或多个完全相同的匹配。但我不明白的是,为什么这在gsub中有效,而在扫描中无效。如果有人能帮我理解原因,我会很感激的。这只是因为他们以一种特殊的方式对待俘虏群体。看医生。清楚了吗?有时,扫描具有该属性是有用的;有时它会妨碍我。我只是注意到我把\1包含在了一个不必要的捕获组中。我不知道这是怎么发生的,也不知道为什么其他人没有指出这一点,但我已经解决了。请注意,在我的回答中,/\1*/就足够了。我不知道第二个捕获组是如何进入我的原始答案的。请注意,在我的答案中,/\1*/就足够了。我不知道第二个俘虏小组是怎么找到我最初的答案的。