使用反向引用和散列时的Ruby gsub问题
以下代码定义了具有正则表达式(键)和替换(值)的哈希。 然后它迭代哈希并相应地替换字符串。
简单的字符串替换效果很好,但是当我需要在替换它之前计算resut(几年到几天的情况发生变化)时,它不会。 并且预先定义哈希是关键。
我错过了什么? 任何帮助将非常感谢。
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!
有两种forms,一种是你传入一个字符串作为第二个参数,其中像$1
和$2
这样的变量引用被相应的子表达式匹配替换,另一种传入一个块,一个块用参数调用传入的子表达式匹配。在调用gsub!
时使用的是块formsgsub!
,但哈希中的字符串试图使用传入字符串的表单。
此外,字符串中的变量插值在匹配之前发生; 一旦对字符串进行求值就会发生变量插值,这是在构造散列时,为了使其工作,你需要在子表达式替换发生后进行变量插值(从来就是这种情况;变量插值会发生)首先,结果字符串将被传递给gsub!
for gsub!
以替换$1
的子表达式匹配,但是$1
已经被评估并且不再在字符串中,因为插值已经发生了)。
现在,如何解决这个问题? 好吧,您可能希望将块直接存储在哈希中(以便在构造哈希时不会解释字符串,而是在gsub!
调用块时),使用与匹配相对应的参数,以及$1
, $2
等等绑定到相应的子表达式匹配。 为了将块转换为可以存储并稍后检索的值,您需要向其添加lambda
; 那么你可以通过在&
前面添加一个块作为块来传递它:
hash = { /(\d+) years/ => lambda { "#{$1.to_f*2} days" }, /cannot/ => lambda { 'of course we CAN' } } hash.each {|k,v| a.gsub!(k, &v) }
当您创建哈希时,表达式"$1.to_f*2" + ' days'
将被执行并存储在哈希中,而不是在您访问哈希时。 从那时起,$ 1还没有价值,它不起作用。
您可以通过将lambda存储在哈希中来解决此问题,如下所示:
hash = {/(\d+) years/ => lambda {|_| "#{$1.to_f * 2} days"}, /cannot/ => lambda {|_| 'of course we CAN'} } hash.each {|k,v| a.gsub!(k, &v) }