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

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

我知道土耳其测试 。 如何在散列之前将输入字符串转换为不区分大小写? 理想情况下,我希望它等同于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 ()工作,但我也没有办法让这种情况不敏感。

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

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

建议使用ToLower(Invariant)的现有答案是错误的:在执行ToLower之后比较字符串等于执行string.Compare(xxxIgnoreCase)。 请参阅此处接受的答案: 字符串比较 – strA.ToLower()== strB.ToLower()或strA.Equals(strB,StringComparisonType)? 它会因某些角色而崩溃。

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

简介:使用CompareInfo.GetSortKey(string).KeyData获取可清除的byte []。 ( MSDN上的GetSortKey )这适用于所有可能的文化。 它也适用于不区分大小写的情况。

因此,对于任何给定字符串(即使使用土耳其语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() ,它使用对象标识而不是值。

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

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

 s = s.ToLowerInvariant(); 

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

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

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