使用反向引用和哈希时的 Ruby gsub 问题

标签 ruby regex hash

以下代码定义了一个包含正则表达式(键)和替换(值)的散列。然后它遍历散列并相应地替换字符串。

简单的字符串替换效果很好,但是当我需要在替换之前计算结果时(年到天变化的情况),它不会。预先定义散列是关键。

我错过了什么?任何帮助将不胜感激。

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;然后你可以通过在它前面加上 &:

来再次将它作为一个 block 传递
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/

相关文章:

php - 警告 : filter_var() [function. 过滤器变量]:未知修饰符 '+'

hash - 方案高阶函数

php - md5 的替代方案,也可在 javascript 中使用

mysql - 如何在 Rails 中表达多表连接

ruby - 字体锁字体关键字区域 : Symbol's function definition is void: compilation--ensure-parse

regex - Vim - 将逻辑注入(inject)正则表达式以操作反向引用

用于传递 URL 和失败 CIDR 掩码的正则表达式

algorithm - 关于向量数据结构设计的问题?

ruby-on-rails - railstutorial.org 中的 SessionsHelper : Should helpers be general-purpose modules for code not needed in views?

ruby:使用散列作为另一个散列的默认值?