【问题标题】:Ruby 1.9 regex as a hash keyRuby 1.9 正则表达式作为哈希键
【发布时间】:2011-07-15 17:28:21
【问题描述】:

我正在使用 ruby 1.9.2p136 (2010-12-25) [i386-mingw32] 尝试这个示例 myhash = {/(\d+)/ => "hello"}
它没有按预期工作(编辑:事实证明它不应该按我的预期工作):

irb(main):004:0> myhash = {/(\d+)/ => "hello"}
=> {/(\d+)/=>"Hello"}
irb(main):005:0> myhash[2222]
=> nil
irb(main):006:0> myhash["2222"]
=> nil

在 ruby​​1.8.7 上的 Rubular 中,regex 有效。
我错过了什么?

【问题讨论】:

标签: ruby regex hash


【解决方案1】:

现在有一个名为 Hashie 的 gem 提供了这个功能(以及更多):https://github.com/intridea/hashie#rash

它提供了一种称为 Rash(regex-hash 的缩写)的数据结构,可以这样使用

myhash = {/(\d+)/ => "hello"}
rash = Hashie::Rash.new(myhash)

>> rash["2222"]
=> "hello"

它确实会尝试将键与正则表达式匹配,因此数字键将不起作用,除非您将它们转换为字符串,您可以通过将 Rash 继承到您自己的类中轻松地做到这一点

【讨论】:

    【解决方案2】:

    您可以将 Jean 的答案放在 default_proc 中

    MAP = {
      /1/ => "one",
      /2/ => "two",
      /\d/ => "number"
    }
    
    MAP.default_proc = lambda do |hash, lookup|
      hash.each_pair do |key, value|
        return value if key =~ lookup
      end
      return nil
    end
    
    p MAP["2"] #=> "two"
    p MAP[44] #=> "number"
    

    【讨论】:

    • 这个答案似乎比公认的更通用。
    【解决方案3】:

    您是否在寻找这种行为?

    myhash = Hash.new{|h,k| h[k] = 'hello' if k =~ /(\d+)/}
    
    p myhash['aaa'] #=> nil
    p myhash #=> {}
    p myhash['1234'] #=>" hello"
    p myhash #=> {"1234"=>"hello"}
    

    【讨论】:

      【解决方案4】:

      如果没有一些额外的代码,它将无法工作,因为您正在将 Regexp 对象与 Integer 或 String 对象进行比较。它们的价值不相等,身份也不相等。它们会匹配,但这需要更改 Hash 类代码。

      irb(main):001:0> /(\d+)/.class
      => Regexp
      irb(main):002:0> 2222.class
      => Fixnum
      irb(main):003:0> '2222'.class
      => String
      irb(main):004:0> /(\d+)/==2222
      => false
      irb(main):007:0> /(\d+)/=='2222'
      => false
      irb(main):009:0> /(\d+)/.equal?'2222'
      => false
      irb(main):010:0> /(\d+)/.equal?2222
      => false
      

      您必须迭代哈希并使用 =~ 如下:

       hash.each do |k,v|    
         unless (k=~whatever.to_s).nil?
           puts v   
         end
       end
      

      或者改变Hash类试试=~除了正常的匹配条件。 (我认为最后一个选项会很困难,在 mri 中,Hash 类似乎有很多 C 代码)

      【讨论】:

        【解决方案5】:

        我从来没有想过使用正则表达式作为哈希键。老实说,我不确定这是否应该起作用,也不知道如果它应该如何起作用。

        无论如何,有两个想法:

        1. 在您尝试查找项目时,您使用hash,但哈希名为myhash
        2. 如果我使用它,我会得到以下结果:

          hektor ~ ❯❯ irb
          >> myhash = {/(\d+)/ => "hello"}
          => {/(\d+)/=>"hello"} 
          >> myhash['2222']
          => nil 
          >> myhash[2222]
          => nil 
          >> myhash[/(\d+)/]
          => "hello" 
          

        这是使用 Ruby 1.9.2-p180。

        好的,检查过,下面是可行的:

        myhash = {/foo/ => "hello"}
        myhash[/foo/] # => "hello"
        

        查找在上,键是一个正则表达式,而不是该正则表达式的许多潜在匹配项之一。

        【讨论】:

        • @Telemachus - 是的 myhash & hash 是我的错字。看起来 ruby​​ 并没有真正将 /(\d+)/ 视为一个正则表达式。
        • @Telemachus - 我遇到了这个 SO 帖子 stackoverflow.com/questions/2082457/…。看起来它应该可以工作。
        • 您链接到的帖子需要一个迭代器和一个对 gsub 的调用,它将解释正则表达式。在您的情况下,您正在尝试分别使用 Integer 和 String 来计算正则表达式对象...
        • @Jean - 现在我也能看到了。
        • @Jonas 这就是重点。你不能让它通过匹配来查找(至少不是直接的)。关键不是匹配,而是正则表达式本身。所以试试myhash[/\d+/](例如),它应该返回"hello"(或者你存储在那里的任何东西。
        猜你喜欢
        • 1970-01-01
        • 2019-11-10
        • 2018-01-12
        • 1970-01-01
        • 2011-07-01
        • 2011-07-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多