【问题标题】:How can I generate a GUID for a string?如何为字符串生成 GUID?
【发布时间】:2010-02-03 09:27:50
【问题描述】:

我在为字符串生成 GUID 时遇到问题 - 例如:

Guid g = New Guid("Mehar");

如何计算"Mehar" 的 GUID?我遇到了一个例外。

【问题讨论】:

  • 你想做什么?您是否尝试根据字符串生成唯一值,在这种情况下您想要散列,例如stackoverflow.com/questions/2112685/…
  • “为字符串生成 GUID”是什么意思?
  • 你想做什么? Guid(string) 接收 guid 格式的字符串,如 {00000000-0000-0000-0000-000000000000}
  • 我怀疑我需要为一个通用字符串(Mehar)生成唯一的 id,就像这样“fc098275-7af6-4780-9bee-624563ec5cb0”

标签: c#


【解决方案1】:

这个帖子很老了,但这就是我们解决这个问题的方法:

由于 .NET 框架中的 Guid 是任意 16 字节或分别为 128 位的,因此您可以通过将任意哈希函数应用于生成 16 字节哈希的字符串并随后将结果传递给 Guid 构造函数来从任意字符串计算 Guid。

我们决定使用 MD5 哈希函数,示例代码如下所示:

string input = "asdfasdf";
using (MD5 md5 = MD5.Create())
{
    byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(input));
    Guid result = new Guid(hash);
}

请注意,此 Guid 生成本身有一些缺陷,因为 它取决于哈希函数的质量!如果您的哈希函数为您使用的大量字符串生成相等的哈希,它将影响您的软件的行为。

以下是产生 128 位摘要的最流行的哈希函数列表:

  • RIPEMD(碰撞概率:2^18)
  • MD4(碰撞概率:肯定)
  • MD5(碰撞概率:2^20.96)

请注意,也可以使用其他哈希函数来产生更大的摘要并简单地截断这些摘要。因此,使用更新的散列函数可能是明智的。列举一些:

  • SHA-1
  • SHA-2
  • SHA-3

今天(2013 年 8 月)160 位 SHA1 哈希可以被认为是一个不错的选择。

【讨论】:

  • 如果您要使用 MD5 哈希数据创建 GUID,您确实应该遵循标准,并表明这是Type 3 guid - 表示数据来自 MD5 哈希。类型 3 GUID 的形式为 xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx,其中 3 表示 Type 3,而 y 被屏蔽为 10xx。您还可以使用 SHA1 哈希(类型 5),将 3 更改为 5。
  • 我会将 Ian 的评论添加到答案中,以帮助澄清您不能只将哈希转换为 GUID:GUID 中的某些位需要特殊值。
  • 我们在这里讨论的是 GUID 而不是 UUID。注意区别。
  • Nachbars,GUID 似乎是微软对 UUID 的实现,这意味着 UUID 规范适用 -- stackoverflow.com/questions/246930/…
  • 除了向第 3 方消费者提供有关使用哪种哈希算法创建 Guid 的信息之外,为什么符合某些位很重要,例如类型 3 指南 ?此信息在比较中起什么作用?
【解决方案2】:

我很确定您已经将 System.Guid 与想要给定字符串的散列(例如,SHA-256)混淆了。

请注意,在选择加密安全散列算法时,MD5、SHA0 和 SHA1 都是generally considered dead。 SHA2 及更高版本仍然可用。

【讨论】:

  • SHA2 如何使用而 SHA1 不可用,如果根据您的链接,SHA2 与 SHA1 具有相同的“弱化”状态,只是从以后的日期开始?
  • 这应该是一条评论。关于作者的猜测和注释。不回答问题。
【解决方案3】:

您正在寻找的可能是生成版本 3 或版本 5 UUID,它们是基于名称的 UUID。 (推荐版本 5)。我认为.NET 框架没有内置支持它。见http://en.wikipedia.org/wiki/Universally_Unique_Identifier

我做了一些谷歌搜索,看看是否可以在 Win32 API 中找到一些东西,但什么也没找到。但是,我确信 .NET 框架在某处隐藏了一些实现,因为据我所知,当在 .NET 中生成 COM 对象并且您不提供显式 GUID 时,.NET 框架会生成一个名称基于 UUID 来创建定义明确的 ClassID 和 InterfaceID,即每次重新编译时都不会更改的 UUID(如 VB6)。但这可能是隐藏的,所以我想你需要自己实现算法。幸运的是,.NET 同时提供了 MD5 和 SHA1 算法,所以我认为实现 version3 和 version5 UUID 应该不会太困难。

【讨论】:

    【解决方案4】:

    我认为您对 Guid 的实际含义有误解。没有诸如“Mehar”之类的字符串的 Guid 表示。

    new Guid(String s) 重载的原因是您可以从一个典型的字符串表示形式创建一个 guid,例如“00000000-0000-0000-0000-000000000000”。

    有关什么是 Guid 的更多信息,请参阅 wiki 文章。

    http://en.wikipedia.org/wiki/Globally_Unique_Identifier

    【讨论】:

      【解决方案5】:

      您不能以这种方式使用 GUID。 constructor of Guid 需要一个有效的 Guid 字符串表示形式。

      您要查找的内容称为哈希函数。 (例如:MD5

      【讨论】:

        【解决方案6】:

        一般来说,制作通用唯一 ID(UUID RFC 4122,又名 GUID)的方法很少。我们可以从 Python 中借用这四个,并在 C# 中制作类似的东西:

        uuid.uuid1([node[, clock_seq]])

        根据主机 ID、序列号和当前时间生成 UUID。 如果没有给出node,则使用getnode()获取硬件 地址。如果给出clock_seq,则作为序号; 否则选择一个随机的 14 位序列号。

        uuid.uuid3(namespace, name)

        根据命名空间标识符(UUID)和名称(字符串)的 MD5 哈希生成 UUID。

        uuid.uuid4()

        生成随机 UUID。

        uuid.uuid5(namespace, name)

        根据命名空间标识符(UUID)和名称(字符串)的 SHA-1 哈希生成 UUID。

        所以如果你需要一个字符串的 ID 作为一个对象,而不是一个值的 ID,你应该用给定的字符串破坏你的私有 UUID, 您的私有 UUID 使用 uuid1 生成一次,然后将其用作 uuid3uuid5 的命名空间。

        维基百科上描述的这些变体和版本Universally_unique_identifier#Variants_and_versions

        【讨论】:

          【解决方案7】:

          如果 op 的意图是从某种字符串哈希(MD5、SHA-1 等)创建 UUID(Guid),我发现这个非常相似的问题和这个很好的答案:

          https://stackoverflow.com/a/5657517/430885

          它有一个指向基于 RFC 4122 §4.3 的 github-sn-p 的链接,该链接将从字符串和命名空间创建一个 Guid(您可以自己选择以防止来自外部环境的冲突)。

          sn-p 的直接链接:https://github.com/LogosBible/Logos.Utility/blob/master/src/Logos.Utility/GuidUtility.cs

          【讨论】:

            【解决方案8】:

            这是我自己的方法,如果可能的话,我有意使用字符串进行十六进制转储 - 从视觉上可以看出至少字符串有多大,如果需要 - 使用一些在线十六进制转换器解码。但是如果字符串太长(超过 16 个字节) - 然后使用 sha-1 计算哈希并从中生成 guid。

            /// <summary>
            /// Generates Guid based on String. Key assumption for this algorithm is that name is unique (across where it it's being used)
            /// and if name byte length is less than 16 - it will be fetched directly into guid, if over 16 bytes - then we compute sha-1
            /// hash from string and then pass it to guid.
            /// </summary>
            /// <param name="name">Unique name which is unique across where this guid will be used.</param>
            /// <returns>For example "{706C7567-696E-7300-0000-000000000000}" for "plugins"</returns>
            static public String GenerateGuid(String name)
            {
                byte[] buf = Encoding.UTF8.GetBytes(name);
                byte[] guid = new byte[16];
                if (buf.Length < 16)
                {
                    Array.Copy(buf, guid, buf.Length);
                }
                else
                {
                    using (SHA1 sha1 = SHA1.Create())
                    {
                        byte[] hash = sha1.ComputeHash(buf);
                        // Hash is 20 bytes, but we need 16. We loose some of "uniqueness", but I doubt it will be fatal
                        Array.Copy(hash, guid, 16);
                    }
                }
            
                // Don't use Guid constructor, it tends to swap bytes. We want to preserve original string as hex dump.
                String guidS = "{" + String.Format("{0:X2}{1:X2}{2:X2}{3:X2}-{4:X2}{5:X2}-{6:X2}{7:X2}-{8:X2}{9:X2}-{10:X2}{11:X2}{12:X2}{13:X2}{14:X2}{15:X2}", 
                    guid[0], guid[1], guid[2], guid[3], guid[4], guid[5], guid[6], guid[7], guid[8], guid[9], guid[10], guid[11], guid[12], guid[13], guid[14], guid[15]) + "}";
            
                return guidS;
            }
            

            【讨论】:

              【解决方案9】:

              Guid 是随机的,它们本质上不会分配给任何字符串或其他值。

              如果您需要此类链接,请将 guid 存储在字典中,并在创建新 guid 之前先检查现有的 guid。

              【讨论】:

              • Guid 不是完全随机的(甚至大部分是随机的,IIRC)。它们遵循严格的格式,因此它们确实可以,但全球唯一,而不仅仅是“可能”唯一:)
              • -1:只有版本 4 GUID 是随机的。实际上,版本 3 GUID 和版本 5 GUID 本质上是分配给字符串的。
              • @DavidCary GUID 版本在哪里描述?你确定你没有考虑 UUID?
              • @Taemyr:在 Wikipedia 的 "Globally unique identifier" 文章中描述了 GUID 版本。是的,我在考虑 UUID,但那篇文章说“GUID 和 RFC 4122 UUID 在以文本方式显示时应该相同”。并暗示每个 GUID 版本算法与对应的 UUID 版本算法相同。
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-12-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多