以下代码定义了一个包含正则表达式(键)和替换(值)的散列。然后它遍历散列并相应地替换字符串。
简单的字符串替换效果很好,但是当我需要在替换之前计算结果时(年到天变化的情况),它不会。预先定义散列是关键。
我错过了什么?任何帮助将不胜感激。
a = "After 45 years we cannot use this thing."
hash = {
/(\d+) years/ => "#{$1.to_f*2}" + ' days',
/cannot/ => 'of course we CAN'
}
hash.each {|k,v|
a.gsub!(k) { v }
}
puts a
谢谢!
最佳答案
String#gsub!
有两种形式,一种是你传入一个字符串作为第二个参数,其中变量引用如 $1
和 $2
被相应的子表达式匹配替换,并且您在其中传入一个 block ,该 block 使用传入子表达式匹配的参数调用。调用 gsub 时使用 block 形式!
,但您的哈希中的字符串正在尝试使用传入字符串的形式。
此外,字符串中的变量插值发生在匹配之前;一旦字符串被评估,变量插值就会发生,这是在你的哈希被构造的时候,而为了这个工作,你需要在子表达式替换发生之后发生变量插值(从来没有这种情况;变量插值会发生首先,结果字符串将传递给 gsub!
for gsub!
以替换 $1
的子表达式匹配,但是 $1
应该已经被评估并且不再在字符串中,因为插值已经发生)。
现在,如何解决这个问题?好吧,您可能希望将 block 直接存储在散列中(以便在构造散列时不会解释字符串,而是在 gsub!
调用 block 时解释),参数对应于匹配,$1
、$2
等绑定(bind)到适当的子表达式匹配。为了将一个 block 变成一个可以存储和以后检索的值,你需要向它添加lambda
;然后你可以通过在它前面加上 &
:
hash = {
/(\d+) years/ => lambda { "#{$1.to_f*2} days" },
/cannot/ => lambda { 'of course we CAN' }
}
hash.each {|k,v|
a.gsub!(k, &v)
}
关于使用反向引用和哈希时的 Ruby gsub 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2082457/