2

我将名称字符串及其 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 () 工作,但我也没有办法让这种情况不区分大小写。

我打赌这是不可能的。如果不是,有什么解决方法?

4

3 回答 3

7

建议使用 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()使用对象标识而不是值。

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

于 2012-05-04T16:50:51.093 回答
6

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

于 2012-05-04T16:03:20.277 回答
2

要使某些内容不区分大小写,请删除大小写:

s = s.ToLowerInvariant();

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

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

您可能一直考虑使用另一种(非不变的)文化,但对于未来的代码维护者来说可能会感到惊讶(通常希望所有字符串操作都使用当前或不变的文化)。

于 2012-05-04T16:07:27.313 回答