当lambda在另一个方法中定义时,lambda中的`regexp.last_match`调用是`nil`

时间:2013-01-16 03:45:12

标签: ruby regex lambda

我在gsub!的replace参数中使用lambda。当lambda以不同的方法定义时,Regexp.last_match$~为空,违反lambda在调用时评估表达式的预期行为。如果我运行此代码,我将收到错误,但如果我取消注释转录中的第一行,它将起作用。

class Test
  def initialize
    @@replace = lambda { "#{callback('*', Regexp.last_match)}" }
  end

  def transcribe(s)
    #@@replace = lambda { "#{callback('*', Regexp.last_match)}" }
    s.gsub!( /(?<l>.?)[aeiou](?<r>.?)/ ) do
      $~[:l] + (@@replace).call + $~[:r]
    end
    s
  end

  def callback( replace, match )
    raise "Error: Match is empty" if match.nil?
    return replace.upcase
  end
end

t = Test.new
puts t.transcribe('example')

有人可以告诉我,我做错了什么,或者这是一个错误吗?

我用Google搜索了它:ruby Regexp.last_match lambda,似乎$1在不同的情况下存在错误,但我无法理解它是否与此相关。

2 个答案:

答案 0 :(得分:1)

正则表达式全局变量(Regexp.last_match只是$〜的访问者)根本不是真正的全局变量。来自last_match的{​​{3}}

  

请注意,last_match是线程的本地   和做法的方法范围   模式匹配。

因此,当您的lambda在不同的方法中定义时,方法范围是不同的,因此它访问自己的私有Regexp.last_match,这是未设置的。最简单的事情可能是将Regexp.last_match作为参数传递给你的lambda

答案 1 :(得分:0)

您可以将匹配作为参数传递给块

s.gsub!( /(?<l>.?)[aeiou](?<r>.?)/ ) do |match|
  $~[:l] + (@@replace).call(match) + $~[:r]
end

这应该可以解决您的问题。

一般情况下,我不会像$~那样使用魔法,除非它与正则表达式位于同一行。它使代码更具可读性。