【问题标题】:Is there a way to pass a regex capture to a block in Ruby?有没有办法将正则表达式捕获传递给 Ruby 中的块?
【发布时间】:2011-01-17 23:31:35
【问题描述】:

我有一个带有 regex 键和 block 值的哈希。类似于以下内容:

{ 'test (.+?)' => { puts $1 } }

显然,不是完全那样,因为块被存储为 Proc,但这就是想法。

我稍后会进行一个正则表达式匹配,看起来很像这样

hash.each do |pattern, action|
    if /#{pattern}/i.match(string)
        action.call
    end
end

这个想法是将块存储在哈希中,以便我将来更容易扩展,但现在regex 捕获不会传递给块。有没有办法干净利落地支持我在regex 中放入的任意数量的捕获(例如,一些regex 模式可能有1 个捕获,其他可能有3 个)?

【问题讨论】:

  • 这并不能解决您的问题,但为什么将模式存储为字符串而不是正则表达式?
  • 没有真正的原因。我正在使用一种方法来存储哈希,因此它更易于阅读(on(pattern, &block) hash[pattern] = block 基本上是我正在使用的方法),并且似乎更容易编写on 'test (.+?)' do puts $1 end

标签: ruby regex block


【解决方案1】:

如果您将比赛数据传递到您的 procs 中会怎样?

hash.each do |pattern, action|
  if pattern.match(string)
    action.call($~)
  end
end

你的哈希会变成:

{ /test (.+?)/i => lambda { |matchdata| puts matchdata[1] } }

【讨论】:

  • 谢谢。我不得不使用matchdata[1] 而不是first,但这很好用。
  • 哦,对了,我应该先测试一下。为了将来,我改变了答案。
【解决方案2】:

我会使用Hash.find 遍历散列元素,将它们传递到一个块中,一次一个。返回true的获胜:

类似这样的:

hash = {/foo/ => lambda { 'foo' }, /bar/ => lambda { 'bar' } }
str = 'foo'
puts hash.find{ |n,v| str =~ n }.to_a.last.call

显然我正在使用lambda,但它已经足够接近了。而且,如果没有匹配项,您需要处理 nil 值。对于我链接to_a.last.call 的示例,但在现实生活中,您希望对 nil 做出反应,否则 Ruby 会发疯。

如果您要搜索大量模式或处理大量文本,您的搜索速度会因每次都必须重新编译正则表达式而减慢。我建议将键存储为正则表达式对象以避免这种情况。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-28
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多