Case不区分大小写的字符串哈希(SHA)

时间:2012-05-04 15:58:46

标签: c# search hash

我将名称字符串及其SHA1值传递到数据库中。 SHA值用作搜索的索引。实现完成后,我们要求使搜索名称不区分大小写。我们确实需要考虑所有语言(汉字是一个真实的用例)。

我知道Turkey Test。如何在散列之前将输入字符串转换为不区分大小写?理想情况下,我希望它等同于InvariantCultureIgnoreCase

换句话说,如何使此函数的输出不区分大小写?

private byte[] ComputeHash(string s)
{
     byte[] data = System.Text.Encoding.Unicode.GetBytes(s ?? string.Empty);
     SHA1 sha = new SHA1CryptoServiceProvider();     // returns 160 bit value
     return sha.ComputeHash(data);
}

如果无法使用SHA,我可以使String.GetHashCode()工作,但我也没有办法让这种情况不敏感。

我打赌这是不可能的。如果不是,有什么工作吗?

3 个答案:

答案 0 :(得分:6)

您可以在生成哈希之前使用s.ToUpperInvariant()。只要你这两种方式(生成原始哈希,并生成一个哈希来测试原始哈希),它就会起作用。

答案 1 :(得分:6)

建议使用ToLower(Invariant)的现有答案是错误的:在执行ToLower之后比较字符串等于执行string.Compare(xxxIgnoreCase)。请参阅此处接受的答案:String comparison - strA.ToLower()==strB.ToLower() or strA.Equals(strB,StringComparisonType)?它会因特定类型的字符而崩溃。

解决方案是为每个字符串创建一个所谓的SortKey。这样的SortKey本质上是一个字节数组,其属性等于字节意味着相等的字符串。 (另外,SortKeys可以以二进制方式进行比较,产生与string.Compare完全相同的顺序。但是我们这里不需要该属性。)

摘要:使用CompareInfo.GetSortKey(string).KeyData获取可清除的字节[]。GetSortKey on MSDN) 这适用于所有可能的文化。它也适用于不区分大小写。

因此,对于任何给定字符串(即使使用土耳其语i),不区分大小写的哈希值可以通过以下方式获得:

var sortKeyBytes = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(anyString,
    CompareOptions.IgnoreCase).KeyData;
int hashCode = HashByteArray(sortKeyBytes); //Need to provide this function.
...

我们不能使用byte []的GetHashCode(),因为byte[]不会覆盖此方法,因此默认使用对象标识而不是值的object.GetHashCode()

您可以使用this answer中的哈希函数。这不好,但它能完成这项工作。

答案 2 :(得分:2)

要使案例不区分大小写,请删除案例:

s = s.ToLowerInvariant();

如果您无法将其存储到数据库中并使用转换其他字符串进行匹配,请不要使用CurrentCulture:

s = s.ToLower(System.Globalization.CultureInfo.CurrentCulture);

您可以考虑始终使用另一种(非Invariant)文化,但对于未来的代码维护者(通常期望所有字符串操作的Current或Invariant文化)可能会令人感到意外。