我将名称字符串及其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()工作,但我也没有办法让这种情况不敏感。
我打赌这是不可能的。如果不是,有什么工作吗?
答案 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文化)可能会令人感到意外。