使用反向引用和散列时的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) }