Ruby gsub 匹配串联

Ruby gsub match concatenation

给定一串数字,我试图在奇数之间插入 '-',在偶数之间插入 '*'。解决方案如下:

def DashInsertII(num)
  num = num.chars.map(&:to_i)
  groups = num.slice_when {|x,y| x.odd? && y.even? || x.even? && y.odd?}.to_a
  puts groups.to_s
    groups.map! do |array|
      if array[0].odd?
      array.join(" ").gsub(" ", "-")
      else
      array.join(" ").gsub(" ", "*")
    end
  end
  d = %w{- *}
  puts groups.join.chars.to_s
  groups = groups.join.chars

 # Have to account for 0 because Coderbyte thinks 0 is neither even nor odd, which is false.

  groups.each_with_index do |char,index|
    if d.include? char
        if (groups[index-1] == "0" || groups[index+1] == "0")
            groups.delete_at(index)
        end
    end
  end
  groups.join
end

很绕,我想知道我是否可以做这样的事情:

"99946".gsub(/[13579][13579]/) {|s,x| s+"-"+x}

其中 s 是第一个奇数,x 第二个。通常当我替换时,我替换匹配的术语,但这里我想保留匹配的术语并在模式之间插入一个字符。这将使这个问题变得更加简单。

这对你有用:

"99946".gsub(/[13579]+/) {|s| s.split("").join("-") }
# => "9-9-946"

这与您尝试的大致相似。它捕获多个连续的奇数位,并使用 gsub 块将它们拆分,然后将它们以“-”分隔。

这将包括协同工作的两种解决方案:

"99946".gsub(/[13579]+/) {|s| s.split("").join("-") }.gsub(/[02468]+/) {|s| s.split("").join("*") }
# => "9-9-94*6"

接受的答案很好地说明了解决问题所需的逻辑。但是,我想建议在生产代码中对其进行一些简化,以便更易于阅读和理解。

特别是,我们用不同的参数做同样的事情两次,因此 reader 通过编写一个都使用调用的方法或 lambda 来使这一点变得明显会有所帮助。例如:

do_pair = ->(string, regex, delimiter) do
  string.gsub(regex) { |s| s.chars.join(delimiter) }
end

那么,可以这样称呼它:

do_pair.(do_pair.('999434432', /[13579]+/, '-'), /['02468']+/, '*')

这可以进一步简化:

do_pair = ->(string, odd_or_even) do
  regex     = (odd_or_even == :odd) ? /[13579]+/ : /['02468']+/
  delimiter = (odd_or_even == :odd) ?    '-'     :     '*'
  string.gsub(regex) { |s| s.chars.join(delimiter) }
end

这种方法的一个优点是它使我们正在处理两种情况(奇数和偶数)以及我们为这两种情况使用的值这一事实变得显而易见。然后可以这样调用:

do_pair.(do_pair.('999434432', :odd), :even)

当然也可以通过方法来实现,这样就好了。我建议使用 lambda 的原因是它的逻辑非常简单,并且在一个方法中仅用于一个(尽管是复合的)表达式。

这无疑更冗长,但将 reader 的逻辑分解为更容易理解的块,减少了理解它的认知成本。

通常的做法是:

"99946"
.gsub(/(?<=[13579])(?=[13579])/, "-")
.gsub(/(?<=[2468])(?=[2468])/, "*")
# => "9-9-94*6"

"99946".gsub(/(?<=[13579])()(?=[13579])|(?<=[2468])()(?=[2468])/){ ? "-" : "*"}
# => "9-9-94*6"
"2899946".each_char.chunk { |c| c.to_i.even? }.map { |even, arr|
  arr.join(even ? '*' : '-') }.join
  #=> "2*89-9-94*6"

步骤:

enum0 = "2899946".each_char
  #=> #<Enumerator: "2899946":each_char>

我们可以将 enum0 转换为数组以查看它将生成的元素:

enum0.to_a
  #=> ["2", "8", "9", "9", "9", "4", "6"]

继续,

enum1 = enum0.chunk { |c| c.to_i.even? }
  #=> #<Enumerator: #<Enumerator::Generator:0x007fa733024b58>:each> 
enum1.to_a
  #=> [[true, ["2", "8"]], [false, ["9", "9", "9"]], [true, ["4", "6"]]] 
a = enum1.map { |even, arr| arr.join(even ? '*' : '-') }
  #=> ["2*8", "9-9-9", "4*6"] 
a.join
  #=> "2*89-9-94*6"