【问题标题】:Replace until all occurrences are removed替换直到所有匹配项都被删除
【发布时间】:2017-03-16 11:55:04
【问题描述】:

我有以下字符串:

",||||||||||||||"
",|||||a|||||,|"

我想实现将所有出现的",|" 替换为",,"

输出应该如下:

",,,,,,,,,,,,,,,"
",,,,,,a|||||,,"

当我在字符串上运行 .gsub(',|', ',,') 时,我得到的不是所需的输出。

",,|||||||||||||"
",,||||a|||||,,"

那是因为它没有多次运行gsub。 有没有类似的递归运行的方法。

【问题讨论】:

  • 这里我们需要更多的描述。你是说当你看到一个逗号后跟一个管道时,用逗号替换它,直到你看到一个非逗号/管道组合?
  • 这是纯 Ruby,与 Rails 无关。
  • @Anthony 你是对的!感谢您的帮助!

标签: ruby-on-rails ruby ruby-on-rails-3 ruby-on-rails-4


【解决方案1】:

正则表达式匹配不能重叠。由于火柴是用来替换的,你不能那样做。这里有两种解决方法:

str = ",|||||a|||||,|"
while str.gsub!(/,\|/, ',,'); end

str = ",|||||a|||||,|"
str.gsub!(/,(\|+)/) { "," * ($1.length + 1) }

【讨论】:

  • 不错。如果您想查看中间步骤:puts str while str.gsub!(/,\|/, ',,')
  • 不错的一个。我只会给出#2(或者至少是#1),因为它只需要一次通过。您是否打算将#2 中的gsub! 更改为gsub(可能是在复制粘贴之后),因为OP 显然不想改变字符串。请注意,#1 也会改变字符串,但您不能在那里进行相同的更改,因为它依赖于 gsub! 在未进行任何更改时返回 nil。此外,#1 不会返回修改后的str,因此如果它包含在方法中,您可能需要str 作为最后一行。我看到你正在接近代表的世纪大关。
【解决方案2】:
smoke_weed_every_day = lambda do |piper|
  commatosed = piper.gsub(',|', ',,')
  commatosed == piper ? piper : smoke_weed_every_day.(commatosed)
end

smoke_weed_every_day.(",||||||||||||||") # => ",,,,,,,,,,,,,,,"
smoke_weed_every_day.(",|||||a|||||,|")  # => ",,,,,,a|||||,,"

【讨论】:

  • 非常聪明的解决方案
【解决方案3】:

来自我的一个旧图书馆。此方法迭代直到块输出等于其输入:

def loop_until_convergence(x)
  x = yield(previous = x) until previous == x
  x
end

puts loop_until_convergence(',||||||||||||||') { |s| s.gsub(',|', ',,') }
# ",,,,,,,,,,,,,,,"
puts loop_until_convergence(',|||||a|||||,|') { |s| s.gsub(',|', ',,') }
# ",,,,,,a|||||,,"

作为奖励,您可以在very few iterations 中计算平方根:

def root(n)
  loop_until_convergence(1) { |x| 0.5 * (x + n / x) }
end

p root(2)
# 1.414213562373095
p root(3)
# 1.7320508075688772

【讨论】:

  • loop_until_convergence 很酷。出于好奇,我发现用泰勒展开式计算root(2) 只需要6 步。
  • @CarySwoveland:据我所知,牛顿的迭代只需要 5 个步骤。 1 不算数,是吗?
  • 对,用@Newton 的方法 5 步。
【解决方案4】:

与@Amandan 的第二个解决方案一样,在没有进一步更改之前无需迭代。

COMMA = ','
PIPE  = '|'

def replace_pipes_after_comma(str)
  run = false
  str.gsub(/./) do |s|
    case s
    when PIPE
      run ? COMMA : PIPE    
    when COMMA
      run = true
      COMMA
    else
      run = false
      s
    end
  end
end

replace_pipes_after_comma ",||||||||||||||"
  #=>                     ",,,,,,,,,,,,,,," 
replace_pipes_after_comma ",|||||a|||||,|"
  #=>                     ",,,,,,a|||||,," 

【讨论】:

    猜你喜欢
    • 2015-07-31
    • 1970-01-01
    • 1970-01-01
    • 2021-06-06
    • 2011-03-28
    • 1970-01-01
    • 1970-01-01
    • 2011-09-10
    • 2012-05-18
    相关资源
    最近更新 更多