如何在Ruby中创建一个比较字符串的哈希值,忽略大小写?

在Ruby中,我想在Hash中存储一些东西,但我不希望它区分大小写。 例如:

h = Hash.new h["HELLO"] = 7 puts h["hello"] 

这应该输出7,即使情况不同。 我可以覆盖哈希的等价方法或类似的东西吗?

谢谢。

为防止此更改完全破坏程序的独立部分(例如您正在使用的其他ruby gems),请为不敏感的哈希创建单独的类。

 class HashClod < Hash def [](key) super _insensitive(key) end def []=(key, value) super _insensitive(key), value end # Keeping it DRY. protected def _insensitive(key) key.respond_to?(:upcase) ? key.upcase : key end end you_insensitive = HashClod.new you_insensitive['clod'] = 1 puts you_insensitive['cLoD'] # => 1 you_insensitive['CLod'] = 5 puts you_insensitive['clod'] # => 5 

在重写赋值和检索function之后,它几乎是蛋糕。 创建Hash的完全替换将需要更加细致地处理完整实现所需的别名和其他函数(例如,#has_key?和#store)。 上述模式可以很容易地扩展到所有这些相关方法。

如果你真的想忽略两个方向的情况并处理像#has_key?这样的所有Hash方法#has_key?#fetch#values_at#delete等,如果你想从头开始构建这个,你需要做一些工作,但如果你创建一个从类ActiveSupport :: HashWithIndifferentAccess扩展的新类,你应该是能够很容易地这样做:

 require "active_support/hash_with_indifferent_access" class CaseInsensitiveHash < HashWithIndifferentAccess # This method shouldn't need an override, but my tests say otherwise. def [](key) super convert_key(key) end protected def convert_key(key) key.respond_to?(:downcase) ? key.downcase : key end end 

这是一些示例行为:

 h = CaseInsensitiveHash.new h["HELLO"] = 7 h.fetch("HELLO") # => 7 h.fetch("hello") # => 7 h["HELLO"] # => 7 h["hello"] # => 7 h.has_key?("hello") # => true h.values_at("hello", "HELLO") # => [7, 7] h.delete("hello") # => 7 h["HELLO"] # => nil 

总的来说,我会说这是一个糟糕的计划; 但是,如果我是你,我会创建一个覆盖[]方法的哈希子类:

 class SpecialHash < Hash def [](search) # Do special code here end end 

没有使用字符串#upcase的任何理由?

 h = Hash.new h["HELLO"] = 7 puts h["hello".upcase] 

如果您坚持修改哈希,则可以执行以下操作

 class Hash alias :oldIndexer :[] def [](val) if val.respond_to? :upcase then oldIndexer(val.upcase) else oldIndexer(val) end end end 

由于它已经启动,您也可以这样做以使设置不区分大小写:

 class Hash alias :oldSetter :[]= def []=(key, value) if key.respond_to? :upcase then oldSetter(key.upcase, value) else oldSetter(key, value) end end end 

我还建议使用module_eval执行此操作。

 require 'test/unit' class TestCaseIndifferentHash < Test::Unit::TestCase def test_that_the_hash_matches_keys_case_indifferent def (hsh = {}).[](key) super(key.upcase) end hsh['HELLO'] = 7 assert_equal 7, hsh['hello'] end end 

虽然Ryan McGeary的方法很有效并且几乎可以肯定是正确的方法,但是有一个我无法辨别原因的错误,它打破了Hash[]方法。

例如:

 r = CaseInsensitiveHash['ASDF', 1, 'QWER', 2] => {"ASDF"=>1, "QWER"=>2} r['ASDF'] => nil ap r { "ASDF" => nil, "QWER" => nil } => {"ASDF"=>1, "QWER"=>2} 

虽然我无法找到或修复该bug的根本原因,但以下hack确实可以改善这个问题:

 r = CaseInsensitiveHash.new(Hash['ASDF', 1, 'QWER', 2]) => {"asdf"=>1, "qwer"=>2} r['ASDF'] => 1 ap r { "asdf" => 1, "qwer" => 2 } => {"asdf"=>1, "qwer"=>2}