如何限制块被调用的次数?

时间:2011-05-16 23:22:09

标签: ruby block

How do I limit the number of replacements when using gsub?中,有人建议采用以下方式进行有限数量的替换:

str = 'aaaaaaaaaa'
count = 5
p str.gsub(/a/){if count.zero? then $& else count -= 1; 'x' end}
# => "xxxxxaaaaa"

它有效,但是代码混合了多少次替换(5)替换应该是什么(“x”如果应该有替换,否则$&。是否有可能将两者分开?

(如果在这种情况下很难将这两件事分开,但可以在其他一些场景中完成,将其作为答案发布)

3 个答案:

答案 0 :(得分:8)

如何将替换作为参数提取并通过在方法内使块关闭来封装计数器?

str = "aaaaaaaaaaaaaaa"

def replacements(replacement, limit)
    count = limit
    lambda { |original| if count.zero? then original else count -= 1; replacement end }
end

p str.gsub(/a/, &replacements("x", 5))

使用替换块可以使其更加通用:

def limit(n, &block)
    count = n
    lambda do |original|
        if count.zero? then original else count -= 1; block.call(original) end
    end
end

现在你可以做像

这样的事情了
p str.gsub(/a/, &limit(5) { "x" })
p str.gsub(/a/, &limit(5, &:upcase))

答案 1 :(得分:2)

gsub会像正则表达式匹配字符串那样经常调用块。阻止这种情况的唯一方法是在块中调用break,但这也会使gsub无法生成有意义的返回值。

所以不,除非你在块中调用break(这会阻止yielding方法中的任何进一步代码运行,从而阻止方法返回任何东西),方法调用块的次​​数完全由方法决定本身。因此,如果您希望gsub仅产生5次,那么唯一的方法是传入一个只与给定字符串匹配五次的正则表达式。

答案 2 :(得分:1)

您为什么使用gsub()?通过它的设计,gsub旨在取代所有出现的东西,所以,就在你正在与它作斗争时。

改为使用sub

str = 'aaaaaaaaaa'
count = 5
count.times { str.sub!(/a/, 'x') }
p str
# >> "xxxxxaaaaa"

str = 'mississippi'
2.times { str.sub!(/s/, '5') }
2.times { str.sub!(/s/, 'S') }
2.times { str.sub!(/i/, '1') }
p str
# >> "m1551SSippi"