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

C# 字符串的不区分大小写哈希(SHA),c#,search,hash,C#,Search,Hash,我正在将名称字符串及其SHA1值传递到数据库中。SHA值用作搜索的索引。在实现完成之后,我们得到了使搜索名称不区分大小写的要求。我们确实需要考虑所有语言(汉字是一个真正的用例) 我知道这件事。如何在哈希之前将输入字符串转换为不区分大小写?理想情况下,我希望它相当于 换句话说,如何使该函数的输出不区分大小写 private byte[] ComputeHash(string s) { byte[] data = System.Text.Encoding.Unicode.GetBytes(

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

我知道这件事。如何在哈希之前将输入字符串转换为不区分大小写?理想情况下,我希望它相当于

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

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不可能,我可能会使()工作,但我也看不到一种使它不区分大小写的方法


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

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

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

s = s.ToLowerInvariant();
如果无法将CurrentCulture存储到数据库中并用于转换匹配的其他字符串,请不要使用CurrentCulture,如:

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

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

< P>建议使用ToLower(不变)的现有答案。错误:在执行ToLower后比较字符串不等于执行字符串。比较(xxxIgnoreCase)。请参见此处公认的答案:它针对某些类型的字符进行分解

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

摘要:使用CompareInfo.GetSortKey(string).KeyData获取可散列字节[]。() 这适用于所有可能的文化。它也适用于案例不敏感

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

var sortKeyBytes = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(anyString,
    CompareOptions.IgnoreCase).KeyData;
int hashCode = HashByteArray(sortKeyBytes); //Need to provide this function.
...
我们不能使用字节[]的GetHashCode(),因为此方法不会被
字节[]
覆盖,因此默认为
对象。GetHashCode()
使用对象标识而不是值


您可以从中使用哈希函数。虽然不太好,但它确实起到了作用。

这不是数据库应该自己做的事情吗?@usr实际上,它可以正常工作。它进一步降低了散列的“强度”,但这应该是显而易见的。您可能不想使用ToLower的不变版本,而是使用特定于区域性的重载。他们在问题中加入了不变量,所以我在这里加入了。您可能还需要字符串。在ToLowerInvariant之前以相同的方式对两个字符串进行规范化。我不熟悉
String.Normalize
。阅读上面的MSDN文档让我想问一位Unicode专家。你可能会问另一个问题,“我应该在散列之前对字符串进行规范化吗?”快速的谷歌搜索并没有发现任何有用的结果。在进行tolower之后比较字符串并不等于进行string.Compare(xxxIgnoreCase)。请参见此处接受的答案:它针对某些类型的字符进行分解。+0。第二个版本是自找麻烦,因为无法保证两个客户都具有相同的区域性。@AlexeiLevenkov很明显,第二个方法只是显示可以选择区域性的一种方法……请检查我对您的答案的编辑是否满意。如果没有,请回滚/更改。这很有趣。我的问题是:生成的排序键有多独特。在散列之前,必须具有唯一的值。既然我不知道答案,我就退出。为什么在散列之前需要唯一的值?结果排序键精确地表示字符串。没有错误的冲突。生成散列的目的是在以后使用该散列与其他内容进行比较。如果在散列之前删除了数据的唯一性,则丢失了要生成的信息。可以指定排序键应表示的比较类型。该方法的定义如下:SortKey GetSortKey(字符串源,CompareOptions)。比较选项包括忽略大小写的选项。SortKey系统的设计目的是准确地表示string.Equals和string.Compare在内部执行的所有操作。完全没有信息丢失。我建议您回答另一个类似的问题()。。。但是现在我在想。。。稳定性呢?Unicode在一段时间内发生更改。。。排序规则会随着时间的推移而变化。。。他们不能改变角色的权重吗?