【问题标题】:Ruby Split string at character difference using regexRuby使用正则表达式在字符差异处拆分字符串
【发布时间】:2016-12-26 01:48:08
【问题描述】:

我目前正在解决一个问题,该问题涉及按每组字符拆分字符串。

例如,

"111223334456777" #=> ['111','22','333','44','5','6','777']

我现在这样做的方式是使用枚举器并将每个字符与下一个字符进行比较,然后以这种方式拆分数组。

res = []
str = "111223334456777"
group = str[0]
(1...str.length).each do |i|
  if str[i] != str[i-1]
    res << group
    group = str[i]
  else
    group << str[i]
  end
end
res << group
res #=> ['111','22','333','44','5','6','777']

我想看看我是否可以使用正则表达式来执行此操作,这将使此过程变得容易得多。我知道我可以将这段代码放在一个方法中,但我很好奇是否可以在这里使用正则表达式。

所以我想做的是

str.split(/some regex/)

产生相同的结果。我考虑过积极的前瞻,但我不知道如何让正则表达式识别角色不同。

有人知道这是否可行吗?

【问题讨论】:

  • 这不能回答你的问题,但你可以写"111223334456777".each_char.slice_when { |a,b| a!=b }.map(&amp;:join) #=&gt; ["111", "22", "333", "44", "5", "6", "777"]
  • @CarySwoveland,你的代码绝对比我的更干净,我写这些代码是为了澄清我在寻找什么。
  • 根据@Stefan 对 Tadman 的回答的评论,以上可以简化为"111223334456777".each_char.slice_when(&amp;:!=).map(&amp;:join)

标签: ruby regex string split


【解决方案1】:
str = "111333224456777"

str.scan /0+|1+|2+|3+|4+|5+|6+|7+|8+|9+/
  #=> ["111", "333", "22", "44", "5", "6", "777"]

str.gsub(/(\d)\1*/).to_a
  #=> ["111", "333", "22", "44", "5", "6", "777"] 

后者使用String#gsub 的(未充分使用的)形式,它接受一个参数且没有块,返回一个枚举数。它只是生成匹配,与字符替换无关。


为了好玩,这里还有其他几种方法可以做到这一点。

str.scan(/((\d)\2*)/).map(&:first)
str.split(/(?<=(.))(?!\1)/).each_slice(2).map(&:first)
str.each_char.slice_when(&:!=).map(&:join)
str.each_char.chunk(&:itself).map { |_,a| a.join }
str.each_char.chunk_while(&:==).map(&:join)
str.gsub(/(?<=(.))(?!\1)/, ' ').split
str.gsub(/(.)\1*/).reduce([], &:<<)  
str[1..-1].each_char.with_object([txt[0]]) {|c,a| a.last[-1]==c ? (a.last<<c) : a << c}

【讨论】:

  • 第二种方式很完美,正是我想要的。谢谢。
  • str.chars.chunk_while { |b,a| b == a }.map(&amp;:join) 也适用于任意输入,可能包括字母等。
  • 嗨,我希望你不介意编辑。我不了解 Ruby,但其他主题中的集合似乎很有价值。也许评论也应该被复制,我无法确定这是否显而易见。
  • @tevemadar,我非常感谢编辑,尽管我会做进一步的小编辑以使其他解决方案符合此处给出的示例字符串。我不知道后来的问题已经结束。不是简单地关闭,而是问题和所有答案都被删除了,这是我以前从未见过的,其目的使我无法理解。
【解决方案2】:

另一个使用group_by 方法的选项,它返回一个散列,其中每个单独的数字作为键,一组数字作为值。

"111223334456777".split('').group_by { |i| i }.values.map(&:join) => => ["111", "22", "333", "44", "5", "6", "777"]

虽然它没有实现正则表达式,但其他人可能会觉得它很有用。

【讨论】:

  • 请注意,这将为"123123"返回["11", "22", "33"]
【解决方案3】:

chunk_while 方法就是您在此处寻找的方法:

str.chars.chunk_while { |b,a| b == a }.map(&:join)

这将破坏当前字符 a 与前一个字符 b 不匹配的任何内容。如果你想限制为数字,你可以做一些预处理。

Enumerable 中有很多非常方便的方法值得探索,而且每个新版本的 Ruby 似乎都添加了更多。

【讨论】:

  • 可简写为str.chars.chunk_while(&amp;:==).map(&amp;:join)
  • ...或str.each_char.chunk_while(&amp;:==).map(&amp;:join) 以避免创建临时数组str.chars
猜你喜欢
  • 1970-01-01
  • 2012-10-02
  • 2017-02-23
相关资源
最近更新 更多