不区分大小写的Bob Jenkins哈希?

时间:2009-10-30 10:34:41

标签: delphi hash delphi-2010

Bob Jenkins哈希函数是否存在不区分大小写的变体?

Generics.Defaults.BobJenkinsHash

提供快速哈希函数。不幸的是,它不能与不区分大小写的比较函数结合使用,如此

TCustomStringComparer = class (TEqualityComparer <String>)
  function Equals(const Left, Right: String): Boolean; override;
  function GetHashCode(const Value: String): Integer; override;
end;
function TCustomStringComparer.Equals (const Left, Right : String) : Boolean;
begin
  Result := CompareText (Left, Right) = 0;
end;
function TCustomStringComparer.GetHashCode (const Value : String) : Integer;
begin
  Result := Generics.Defaults.BobJenkinsHash (Value [1], Length (Value) * SizeOf (Char), 0);
end;

这是因为TDictionary首先比较哈希码,然后在检查相等时使用提供的比较器。

当然我可以在我的GetHashCode函数中使用UpperCase,但我想知道如果我能以某种方式修改哈希函数本身会更快。

4 个答案:

答案 0 :(得分:8)

不,哈希函数没有大小写不变的版本。在将所有字符串传递给哈希函数之前,将所有字符串置大小写。

答案 1 :(得分:3)

它会稍快一些,但会严重损害您的可维护性。这种微优化很少有充分的理由。只需像你建议的那样在散列之前将字符串转换为小写或大写。

  

“我们应该忘记小事   效率,约占97%   时间:过早优化是   万恶之源。但我们不应该   放弃我们的机会   至关重要3%。一个优秀的程序员会   不被这样的自满所哄骗   推理,他会明智地看   仔细阅读关键代码;但   只有在那段代码之后   确定“ - 唐纳德克努特

答案 2 :(得分:3)

IMO整个问题都是错误的。引用Wikipedia article on hash functions

  

哈希函数是任何定义良好的过程或数学函数,它将大量可能可变大小的数据转换为小数据,通常是一个可作为索引的单个整数。一个数组。

注意“数据量” - 没有指定类型,实际上Bob Jenkins散列函数有一个无类型参数const Data指向要散列的数据。由于输入数据不一定是字符序列,因此无法计算“不区分大小写”的散列值。即使它是一系列字符 - 上层或下层也依赖于字符集和编码。所以你需要为ASCII字符串,UTF-8编码字符串,UTF-16 LE编码字符串,...(你明白了)提供不同的哈希函数。

答案 3 :(得分:0)

我还需要在项目中使用这样的功能。 Bob Jenkin的一次性哈希:

function hash(const s: string): cardinal;
var
  p, last: PByte;
begin
  if s = '' then exit(1);
  p := pbyte(pointer(s));
  last := p + length(s);
  result := 0;
  while p < last do begin
    if {$ifdef asciionly}p^ < 128{$else}true{$endif}  then begin
      result := result + p^;
      if (p^ >= ord('a')) and (p^ <= ord('z')) then result := result - ord('a') + ord('A');
      result := result + (result shl 10);
      result := result xor (result shr 6);
    end;
    inc(p);
  end;

  result := result + (result shl 3);
  result := result xor (result shr 11);
  result := result + (result shl 15);
end;        

如果设置了asciionly,它也应该为utf-8和latin1字符串提供相同的哈希值。

不要忘记禁用溢出检查。