我有以下两个字符串:
var string1 = "MHH2016-05-20MASTECH HOLDINGS, INC. Financialshttp://finance.yahoo.com/q/is?s=mhhEDGAR Online FinancialsHeadlines";
var string2 = "CVEO2016-06-22Civeo upgraded by Scotia Howard Weilhttp://finance.yahoo.com/q/ud?s=CVEOBriefing.comHeadlines";
乍一看,这两个字符串不同,但使用
GetHashCode method
,它们的哈希码是相同的。
var hash = 0;
var total = 0;
foreach (var x in string1) //string2
{
//hash = x * 7;
hash = x.GetHashCode();
Console.WriteLine("Char: " + x + " hash: " + hash + " hashed: " + (int) x);
total += hash;
}
两个字符串的总数最终均为 620438779。是否有另一种方法可以返回更独特的哈希码?我需要基于字符串中的字符的哈希码是唯一的。尽管两个字符串不同并且代码工作正常,但这两个字符串加起来却是相同的。我如何改进此代码以使它们更加独特?
string.GetHashCode
确实不适合真正的哈希:
警告
哈希码旨在在基于哈希表的集合中进行高效插入和查找。哈希码不是永久值。为此:
- 不要序列化哈希码值或将它们存储在数据库中。
- 不要使用哈希码作为从键控集合中检索对象的键。
- 请勿使用哈希码代替加密哈希函数返回的值。对于加密哈希,请使用从
或System.Security.Cryptography.HashAlgorithm
类派生的类。System.Security.Cryptography.KeyedHashAlgorithm
- 不要通过测试哈希码是否相等来确定两个对象是否相等。 (不同的对象可以具有相同的哈希码。)要测试相等性,请调用
或ReferenceEquals
方法。Equals
并且很有可能重复。
HashAlgorithm.ComputeHash
。示例稍作更改,使用 SHA256 而不是 MD5,如 @zaph 建议的那样:
static string GetSha256Hash(SHA256 shaHash, string input)
{
// Convert the input string to a byte array and compute the hash.
byte[] data = shaHash.ComputeHash(Encoding.UTF8.GetBytes(input));
// Create a new Stringbuilder to collect the bytes
// and create a string.
StringBuilder sBuilder = new StringBuilder();
// Loop through each byte of the hashed data
// and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
{
sBuilder.Append(data[i].ToString("x2"));
}
// Return the hexadecimal string.
return sBuilder.ToString();
}
using System.Security.Cryptography;
string data="test";
byte[] hash;
using (MD5 md5 = MD5.Create())
{
md5.Initialize();
md5.ComputeHash(Encoding.UTF8.GetBytes(data));
hash = md5.Hash;
}
hash 是一个 16 字节数组,您可以将其转换为某些十六进制字符串或 base64 编码字符串进行存储。
编辑:
该哈希码的用途是什么?
从
hash(x) != hash(y)
你可以推导出x!=y
,但是
从
hash(x) == hash(y)
你不能推导出x==y
一般!
我也遇到了和你类似的问题 我通过以下方式解决了这个问题,并使用测试软件测试了多达5000万个文本,所有这些文本都是英文的,测试它们没有问题,但是可以肯定的是,考虑到输入数据的统计总体,完全合乎逻辑的是,它不可能对于任何字符串长度的字符串的所有情况,都会产生唯一的长数值,但是对于具有特殊且有意义的条件的字符串,例如表和列的名称,此方法可以是用过的。 如果有更好的解决方案,请指导我
public class ContextIdGenerator
{
public long CreateTableId(string schemaName, string tableName) => CreateId($"{schemaName}.{tableName}", false, Encoding.ASCII);
public long CreateTableColumnId(string schemaName, string tableName, string columnName) => CreateId($"{schemaName}.{tableName}.{columnName}", false, Encoding.ASCII);
public long CreateId(string context, bool sensitive, Encoding encoding)
{
if (string.IsNullOrEmpty(context)) return 0;
if (!sensitive) context = context.ToUpper();
using var hasher = MD5.Create();
var bytes = encoding.GetBytes(context.ToUpper());
var hBytes = hasher.ComputeHash(bytes);
return hBytes.Select((q, i) => Convert.ToInt64(q * Math.Pow(10, i + 1))).Sum();
}
}
下面提到测试源(ASCII状态)
private static Random random = new Random();
public static string RandomString(int length)
{
const string chars = ".ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
private void TestButton_Click(object sender, EventArgs e)
{
Enabled = false;
Dictionary<long, string> db = new();
var A = new ContextIdGenerator();
var errorCounter = 0;
var counter = 0;
while (counter <= 50000000)
{
Application.DoEvents();
var len = random.Next(20, 30);
var text = RandomString(len);
var keyId = A.CreateId(text, false, Encoding.ASCII);
counter++;
if (keyId == 0) continue;
try
{
db.Add(keyId, text);
}
catch
{
if (db.Values.Contains(text, StringComparer.OrdinalIgnoreCase))
continue;
errorCounter++;
}
}
Enabled = true;
MessageBox.Show($"ErrorCount : {errorCounter}");
}