根据String生成唯一的Hash码

问题描述 投票:0回答:3

我有以下两个字符串:

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。是否有另一种方法可以返回更独特的哈希码?我需要基于字符串中的字符的哈希码是唯一的。尽管两个字符串不同并且代码工作正常,但这两个字符串加起来却是相同的。我如何改进此代码以使它们更加独特?

c#
3个回答
41
投票

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();
}

8
投票
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
一般!


0
投票

我也遇到了和你类似的问题 我通过以下方式解决了这个问题,并使用测试软件测试了多达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}");
}
© www.soinside.com 2019 - 2024. All rights reserved.