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"
给定一串数字,我试图在奇数之间插入 '-'
,在偶数之间插入 '*'
。解决方案如下:
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"