比较相等的字符串在哈希中找不到相同的对象

Posted

技术标签:

【中文标题】比较相等的字符串在哈希中找不到相同的对象【英文标题】:Strings that compare equal don't find same objects in Hash 【发布时间】:2014-07-19 17:07:36 【问题描述】:

我有两个看起来相等的字符串:

context = "Marriott International World’s Most ADMIRED Lodging Company by FORTUNE for 14th yr. via @FortuneMagazine http://cnnmon.ie/1kcFZSQ"
slice_str = context.slice(105,24) # => "http://cnnmon.ie/1kcFZSQ"
str = "http://cnnmon.ie/1kcFZSQ"

slice_str == str                  # => true
slice_str.eql? str                # => true

但是,当我在键是字符串的哈希中查找值时,它们在 Ruby 2.1.0 和 Ruby 2.1.1 中返回的内容不同:

redirects = "http://cnnmon.ie/1kcFZSQ"=>""
redirects.key?(slice_str)         # => false
redirects.key?(str)               # => true

对这种行为有什么解释? Ruby 1.9.3 按预期工作。

【问题讨论】:

嗯。而redirects.keys.include? slice_strtrue 上面的对我来说效果很好,为redirects.key?(slice_str)返回真值再试一次。 @anusha 您是否重新键入或复制/粘贴它?什么红宝石版本? 显然这是 ruby​​ 2.0 中的一个错误,在此处报告 -bugs.ruby-lang.org/issues/9882 并在此处修复 bugs.ruby-lang.org/projects/ruby-trunk/repository/revisions/…... 其实你应该让@sawa 去做,因为我只是从他删除的答案中复制了这些信息...... 【参考方案1】:

对于Hash 键,其key#hash 方法确定键是否相等。

在您的示例中,在 ruby​​ 2.1.1 中,这两个字符串散列 不同:

slice_str.hash == str.hash # => false in Ruby 2.1.1

虽然,我完全不清楚为什么切片字符串具有不同的哈希值。 更奇怪的是——我发现如果你在纯 ASCII 字符串上测试代码(你的字符串,但用' 而不是)——哈希值是一样的!

真的很奇怪。

我找到的唯一解决方案(虽然看起来一点也不优雅):

slice_str = context.slice(105,24).chars.join # split it into separate chars and then join back
p str.hash == slice_str.hash # true now
p redirects.key?(slice_str) # true now

UPD:糟糕,我没有在上面的 cmets 中看到指向错误的链接 :(

【讨论】:

我不知道@sawa为什么撤回了他的回答,但他发现slice的多字节字符有问题;哈希值的差异只是一个副产品。 @CarySwoveland。是的,我现在明白了。不过,我并没有因为它提供了一些(非常愚蠢的)解决方法而撤回了我的答案。【参考方案2】:

这是 ruby​​

$ rvm use 2.1.2
Using /Users/richniles/.rvm/gems/ruby-2.1.2
$ irb
2.1.2 :001 > context = "Marriott International World’s Most ADMIRED Lodging Company by FORTUNE for 14th yr. via @FortuneMagazine http://cnnmon.ie/1kcFZSQ"
 => "Marriott International World’s Most ADMIRED Lodging Company by FORTUNE for 14th yr. via @FortuneMagazine http://cnnmon.ie/1kcFZSQ" 
2.1.2 :002 > slice_str = context.slice(105,24) # => "http://cnnmon.ie/1kcFZSQ"
 => "http://cnnmon.ie/1kcFZSQ" 
2.1.2 :003 > str = "http://cnnmon.ie/1kcFZSQ"
 => "http://cnnmon.ie/1kcFZSQ" 
2.1.2 :004 > redirects = "http://cnnmon.ie/1kcFZSQ"=>""
 => "http://cnnmon.ie/1kcFZSQ"=>"" 
2.1.2 :005 > redirects.key?(slice_str) 
 => false 
2.1.2 :006 > redirects.key?(str)  
 => true 

但在 ruby​​ 2.1.3 中做同样的事情:

 $ rvm use 2.1.3
 Using /Users/richniles/.rvm/gems/ruby-2.1.3
 $ irb
 2.1.3 :001 > context = "Marriott International World’s Most ADMIRED Lodging Company by FORTUNE for 14th yr. via @FortuneMagazine http://cnnmon.ie/1kcFZSQ"
  => "Marriott International World’s Most ADMIRED Lodging Company by FORTUNE for 14th yr. via @FortuneMagazine http://cnnmon.ie/1kcFZSQ" 
 2.1.3 :002 > slice_str = context.slice(105,24) # => "http://cnnmon.ie/1kcFZSQ"
  => "http://cnnmon.ie/1kcFZSQ" 
 2.1.3 :003 > str = "http://cnnmon.ie/1kcFZSQ"
  => "http://cnnmon.ie/1kcFZSQ" 
 2.1.3 :004 > redirects = "http://cnnmon.ie/1kcFZSQ"=>""
  => "http://cnnmon.ie/1kcFZSQ"=>"" 
 2.1.3 :005 > redirects.key?(slice_str) 
  => true 
 2.1.3 :006 > redirects.key?(str)  
  => true 

【讨论】:

它也被向后移植到 Ruby 2.0 - bugs.ruby-lang.org/issues/9882#note-6

以上是关于比较相等的字符串在哈希中找不到相同的对象的主要内容,如果未能解决你的问题,请参考以下文章

java的hashcode用来判断对象是否相等

为啥JAVA不可以用“==”来比较两个字符串是不是相等?

如果两个对象的哈希码相同则他们不一定相同,如果对象一致则哈希码一定相同

有两个相等的字符串会给出相同的哈希值

java Object里的equals比较的是对象的哈希值还是物理内存? "==" 比较的又啥?

CTF之MD5相等值不相等