当没有一个被替换的模式保证匹配时,在字符串上进行多个就地替换的最惯用的方法是什么?
例如,假设我有一个字符串数组,我想在每个字符串中将“sad”替换为“happy”,将“goodbye”替换为“hello”:
a = ["I am sad", "goodbye for now"]
# This will work:
a.map! do |s|
s = s.gsub(/sad/,"happy").gsub(/goodbye/,"hello")
end
# So will this:
a.each do |s|
s.gsub!(/sad/,"happy")
s.gsub!(/goodbye/,"hello")
end
# This will fail when s does not match /sad/:
a.each do |s|
s.gsub!(/sad/,"happy").gsub!(/goodbye/,"hello")
end
第一个选项似乎有点傻,因为逻辑上我正在尝试进行就地替换而不是重新分配。第二种选择是可以的,但我的审美意识告诉我,要求将替换变成两个连续的陈述似乎是错误的,特别是在预期只有一个或另一个替换成功的情况下(具有讽刺意味的是,确切地说)导致第三个版本(看起来对我来说)失败的情况。此外,我在这里使用each
破坏性可能是错误的,但如果我使用map!
代替,我需要添加s
作为块中的最后一行确保在替换失败时我不会意外地发出nil
个条目,这似乎比第一个选项差一些。
我猜测(g)sub!
方法在没有进行替换时返回nil
的原因是因为这使得它们便于在逻辑结构中使用,这无疑是一个很好的理由(特别是因为非破坏性版本显然必须返回“真实”值,无论如何)。
所以...我知道这实际上只是一个小小的美学狡辩,但是有没有比我展示的两种(工作)方式更好的方法?如果没有,是否有理由偏爱另一个(超出我对第二个版本的直观审美偏好)?
答案 0 :(得分:7)
首先,您需要创建一个replacement_hash
,如下所示:
replacement_hash = { "sad" => "happy", "goodbye" => "hello"}
a = ["I am sad", "goodbye for now"]
Regexp.union(replacement_hash.keys) # => /sad|goodbye/
a.map { |s| s.gsub(Regexp.union(replacement_hash.keys), replacement_hash) }
# => ["I am happy", "hello for now"]
如果需要就地替换,请执行以下操作: -
a.each { |s| s.gsub!(Regexp.union(replacement_hash.keys), replacement_hash) }