如何为一个字符串生成GUID?

66

我遇到了一个问题,需要为一个字符串生成GUID - 例如:

Guid g = New Guid("Mehar");

如何计算"Mehar"的GUID?我一直遇到异常。


1
你想做什么?你是想基于字符串生成唯一值,这种情况下你需要哈希,例如:https://dev59.com/gnI95IYBdhLWcg3w3yFU - Unsliced
“生成字符串的GUID”是什么意思? - Jon Skeet
你在尝试做什么,Mehar?Guid(string)接收一个格式为{00000000-0000-0000-0000-000000000000}的GUID字符串。 - Rubens Farias
我的疑问是,我需要为一个一般的字符串(Mehar)生成唯一的ID,就像这样“fc098275-7af6-4780-9bee-624563ec5cb0”。 - Mehar
1
请参见此处:https://dev59.com/s3E85IYBdhLWcg3wtV_1 - RenniePet
10个回答

139

虽然这个帖子很老,但我们是这样解决这个问题的:

由于 .NET框架中的Guid是任意的16字节(或者说128位),所以你可以通过将任意字符串应用任何生成16字节哈希的哈希函数来计算Guid,并随后将结果传递给Guid构造函数。

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

string input = "asdfasdf";
using (MD5 md5 = MD5.Create())
{
    byte[] hash = md5.ComputeHash(Encoding.UTF8.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哈希值可以被认为是一个不错的选择。

27
如果您要通过MD5哈希数据创建GUID,那么您应该遵循标准,并指示这是一个Type 3 guid - 意味着数据来自MD5哈希。 Type 3 GUID的形式为 xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx,其中**3**表示Type 3,y掩码为10xx。您还可以使用SHA1哈希(Type 5),其中将3更改为5。 - Ian Boyd
2
我们在这里谈论的是GUID而不是UUID。请注意区别。 - Nachbars Lumpi
8
看起来,GUID是Microsoft对UUID的实现,这意味着UUID规范适用。 - Mihai Danila
2
除了向第三方客户提供有关用于创建 Guid 的哈希算法的信息外,符合某些位(例如 Type 3 Guid)的重要性是什么?这些信息在比较中扮演什么角色? - BaltoStar
1
请使用稳定的 Encoding(最好是 Encoding.UTF8),而不是 Encoding.Default - CodeAngry
显示剩余4条评论

18

我相当确定你将System.Guid与想要给定字符串的哈希(如SHA-256)混淆了。

请注意,在选择加密安全哈希算法时,MD5、SHA0和SHA1通常被认为是不可用的。 SHA2及以上仍然可用。


如果根据您提供的链接,SHA2和SHA1都被标记为“削弱”,那么为什么SHA2可用而SHA1不可用?这是为什么? - Ruslan
3
这应该是一条评论。关于作者的猜测和一则注释。并没有回答问题。 - Edward Olamisan

7
你要找的可能是生成版本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算法,因此我认为实现版本3和版本5 UUID应该不太困难。

5
我认为您对Guid的实际含义有所误解。像"Mehar"这样的字符串没有Guid表示。 new Guid(String s)重载是为了能够从典型的Guid字符串表示中创建Guid,例如"00000000-0000-0000-0000-000000000000"。
有关Guid实际含义的更多信息,请参见维基百科文章。 http://en.wikipedia.org/wiki/Globally_Unique_Identifier

4

您不能以那种方式使用GUID。 Guid的构造函数要求一个有效的Guid字符串表示。

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


4
通常有几种方法可以生成通用唯一标识符(UUID RFC 4122,又称GUID)。我们可以从Python中借鉴这四个方法,并在C#中创建类似的内容: uuid.uuid1([node[, clock_seq]]) 生成一个基于主机ID、序列号和当前时间的UUID。如果未给出节点,则使用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


4

这里是我的方法,如果可能的话,我故意使用字符串转十六进制转储-至少可以看到字符串有多大,如果需要-使用一些在线十六进制转换器进行解码。但是,如果字符串太长(超过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;
}

3
如果操作者的目的是从某种字符串哈希(MD5、SHA-1等)中创建UUID(Guid),我发现了一个非常相似的问题,并且有一个很好的答案:

https://dev59.com/s3E85IYBdhLWcg3wtV_1#5657517

这里有一个基于RFC 4122 §4.3的github代码片段,它可以通过一个字符串和命名空间创建一个Guid(你可以选择自己的命名空间来确保不受外部环境的干扰)。

代码片段的直接链接: https://github.com/LogosBible/Logos.Utility/blob/master/src/Logos.Utility/GuidUtility.cs


0
你可以从短语词中生成GUID,以下是方法:
SHA256 sHA256 = SHA256.Create();
var byte32hash = sHA256.ComputeHash(Encoding.UTF8.GetBytes("myphrase"));
var guid = BitConverter.ToString(byte32hash.Take(16).ToArray()).Replace("-", "").ToLower();
var id = Guid.Parse(guid);

感谢您对Stack Overflow社区做出贡献的兴趣。这个问题已经有了相当多的答案,其中一个答案已经得到社区的广泛验证。您确定您的方法之前没有被提到过吗?如果是这样的话,能否解释一下您的方法有何不同,什么情况下可能更适用您的方法,以及为什么您认为之前的答案不够满意。您能否编辑您的答案并提供解释? - undefined

-2

Guid是随机的,它们并不固有地分配给任何字符串或其他值。

如果您需要这样的链接,请将guid存储在字典中,并在创建新的guid之前首先检查是否存在该guid。


3
Guid并不完全是随机的,或者说即使在大多数情况下也不是随机的。它们遵循严格的格式,以确保它们是全局唯一的,而不仅仅是“可能”的唯一。 :) - Noon Silk
2
-1:只有版本4的GUID是随机的。实际上,版本3和版本5的GUID都是固定分配给一个字符串的。 - David Cary
@DavidCary GUID版本在哪里描述?你确定你不是在想UUID吗? - Taemyr
@Taemyr:GUID版本在维基百科的“全局唯一标识符”文章中有详细描述。是的,我正在考虑UUID,但该文章表示:“在文本显示时,GUID和RFC 4122 UUID应该相同。”,暗示每个GUID版本算法与相应的UUID版本算法相同。 - David Cary
@Taemyr: "GUID和UUID有什么区别吗?". - David Cary
@DavidCary 正确。但GUID经常是特定的UUID实现。特别是.NET生成的Guid是版本4 GUID,因此是随机的。 - Taemyr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接