【问题标题】:YouTube-like GUID类似 YouTube 的 GUID
【发布时间】:2010-11-30 07:36:35
【问题描述】:

是否可以像在 YouTube (N7Et6c9nL9w) 中那样生成短 GUID?

怎么做?我想在网络应用中使用它。

【问题讨论】:

标签: c# .net url-shortener


【解决方案1】:

你可以使用 Base64:

string base64Guid = Convert.ToBase64String(Guid.NewGuid().ToByteArray());

这会生成一个类似E1HKfn68Pkms5zsZsvKONw== 的字符串。由于 GUID 始终为 128 位,因此您可以省略 ==,您知道它将始终出现在末尾,这将为您提供 22 个字符的字符串。不过,它不像 YouTube 那样短。

【讨论】:

  • 这种方法的缺点是,生成的值可以包含斜杠(/)符号,处理不当会不方便在Url中使用
  • 虽然我真的很喜欢这个解决方案,但我同意 Jhonny D 的观点。不仅会出现“/”,而且还会出现“+”,这会完全破坏您的网址。 叹息
  • 只需将“/”和“+”替换为 URL 安全字符,例如“-”和“_”。然后,在重新读取 guid 时,在解码之前将它们替换回来。
  • Jhonny D. 提到的问题的解决方案是将有问题的字符('+' 和 '/')替换为 url 友好字符(例如,'-' 和 '_')。
  • 因此,通过将有问题的字符('+' 和 '/')替换为对 url 友好的字符(例如,'-' 和 '_'),仍然可以保证它是唯一的 Guid 吗?
【解决方案2】:

如已接受的答案中所述,如果您在 URL 中使用 GUID,可能会导致问题。这是一个更完整的答案:

    public string ToShortString(Guid guid)
    {
        var base64Guid = Convert.ToBase64String(guid.ToByteArray());

        // Replace URL unfriendly characters with better ones
        base64Guid = base64Guid.Replace('+', '-').Replace('/', '_');

        // Remove the trailing ==
        return base64Guid.Substring(0, base64Guid.Length - 2);
    }

    public Guid FromShortString(string str)
    {
        str = str.Replace('_', '/').Replace('-', '+');
        var byteArray = Convert.FromBase64String(str + "==");
        return new Guid(byteArray);
    }

用法:

        var guid = Guid.NewGuid();
        var shortStr = ToShortString(guid);
        // shortStr will look something like 2LP8GcHr-EC4D__QTizUWw
        var guid2 = FromShortString(shortStr);
        Assert.AreEqual(guid, guid2);

【讨论】:

  • 既然你知道 Base64 字符串的长度总是 22 个字符而没有填充,你不能只用 base64Guid.Substring(0, 22) 而不是 base64Guid.Substring(0, base64Guid.Length - 2) 吗?
  • 是的,这两个选项是等效的。我认为我的版本使操作更加清晰。
  • 字符串替换是对现有答案的修复,那么为什么不 Guid.NewGuid().ToString("N") 呢?
  • guid.ToString("N") 将返回一个 32 个字符的字符串,这不是真正的迷你。替换是针对该 guid 的 base64 编码,因为 base64 默认使用 / 和 + 作为字符,我们不想要这些。
【解决方案3】:

9 个字符不是 GUID。鉴于此,您可以使用 int 的十六进制表示,它为您提供 8 个字符的字符串。

您可以使用您可能已经拥有的 id。您也可以对不同的简单类型使用.GetHashCode,并且您有不同的int。您还可以异或不同的字段。如果你喜欢它,你甚至可以使用随机数 - 嘿,如果你坚持积极的态度,你的可能值远高于 2.000.000.000 ;)

【讨论】:

    【解决方案4】:

    这不是 GUID

    让我进入以下内容

    它使用来自EPOCHTotalMilliseconds 和一组有效的字符。

    这不会是全局唯一的,但对于它定义的实例来说是唯一的

    public string YoutubeLikeId()
    {
        Thread.Sleep(1);//make everything unique while looping
        long ticks = (long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1,0,0,0,0))).TotalMilliseconds;//EPOCH
        char[] baseChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
        
        int i = 32;
        char[] buffer = new char[i];
        int targetBase= baseChars.Length;
    
        do
        {
            buffer[--i] = baseChars[ticks % targetBase];
            ticks = ticks / targetBase;
        }
        while (ticks > 0);
    
        char[] result = new char[32 - i];
        Array.Copy(buffer, i, result, 0, 32 - i);
    
        return new string(result);
    }
    

    输出将类似于

    XOTgBsu
    XOTgBtB
    XOTgBtR
    XOTgBtg
    XOTgBtw
    XOTgBuE
    

    更新:同样可以通过Guid 实现

    var guid = Guid.NewGuid(); 
    guid.ToString("N");
    guid.ToString("N").Substring(0,8);
    guid.ToString("N").Substring(8,4);
    guid.ToString("N").Substring(12,4);
    guid.ToString("N").Substring(16,4);
    guid.ToString("N").Substring(20,12);
    

    对于 Guid ecd65132-ab5a-4587-87b8-b875e2fe0f35,它会将其分解为 ecd65132 ,ab5a , 4587,87b8,b875e2fe0f35

    但我不能保证它总是独一无二的。

    更新 2: 还有一个名为 ShortGuid 的项目来获得一个 url 友好的 GUID 它可以从 / 转换为常规的 Guid

    它的工作原理是将Guid 编码为 Base64,如下面的代码

    public static string Encode(Guid guid)
    {
        string encoded = Convert.ToBase64String(guid.ToByteArray());
    
        encoded = encoded
            .Replace("/", "_")
            .Replace("+", "-");
        return encoded.Substring(0, 22);
    }
    

    它的好处是可以再次解码以获取Guid

    public static Guid Decode(string value)
    {
        // avoid parsing larger strings/blobs
        if (value.Length != 22)
        {
            throw new ArgumentException("A ShortGuid must be exactly 22 characters long. Receive a character string.");
        }
    
        string base64 = value
            .Replace("_", "/")
            .Replace("-", "+") + "==";
    
        byte[] blob = Convert.FromBase64String(base64);
        var guid = new Guid(blob);
    
        var sanityCheck = Encode(guid);
        if (sanityCheck != value)
        {
            throw new FormatException(
                @"Invalid strict ShortGuid encoded string. The string '{value}' is valid URL-safe Base64, " +
                @"but failed a round-trip test expecting '{sanityCheck}'."
            );
        }
    
        return guid;
    }
    

    所以 Guid 4039124b-6153-4721-84dc-f56f5b057ac2 将被编码为 SxI5QFNhIUeE3PVvWwV6wg 并且输出看起来像这样。

    ANf-MxRHHky2TptaXBxcwA
    zpjp-stmVE6ZCbOjbeyzew
    jk7P-XYFokmqgGguk_530A
    81t6YZtkikGfLglibYkDhQ
    qiM2GmqCK0e8wQvOSn-zLA
    

    【讨论】:

      【解决方案5】:

      正如其他人所提到的,YouTube 的 VideoId 在技术上并不是一个 GUID,因为它本身并不是唯一的。

      根据Wikipedia

      唯一键的总数为 2128 或 3.4×1038。这个数字太 大到随机生成相同数字的概率 两次可以忽略不计。

      YouTube 的 VideoId 的独特性由他们的生成器算法维护。

      您可以编写自己的算法,也可以使用某种随机字符串生成器并利用 SQL 中的UNIQUE CONSTRAINT 约束来强制其唯一性。

      首先,在您的数据库中创建一个UNIQUE CONSTRAINT

      ALTER TABLE MyTable
      ADD CONSTRAINT UniqueUrlId
      UNIQUE (UrlId);
      

      然后,例如,生成一个随机字符串(来自 philipproplesch 的answer):

      string shortUrl = System.Web.Security.Membership.GeneratePassword(11, 0);
      

      如果生成的UrlId 足够随机且足够长,您应该很少遇到SQL 遇到重复的UrlId 时引发的异常。在这种情况下,您可以轻松地在 Web 应用中处理异常。

      【讨论】:

      • GeneratePassword 方法的唯一问题是第二个参数实际上是针对非字母和非数字字符的最小数量。当我尝试使用0 时,我得到了几个这样的符号......
      【解决方案6】:

      从技术上讲,它不是 Guid。 Youtube 有一个简单的随机字符串生成器,您可以使用一组允许的字符和一个随机数生成器在几分钟内完成它。

      【讨论】:

        【解决方案7】:

        这可能不是最好的解决方案,但您可以这样做:

        string shortUrl = System.Web.Security.Membership.GeneratePassword(11, 0);
        

        【讨论】:

        • 这个方法唯一的问题是第二个参数实际上是非字母和非数字字符的最小数量。当我尝试使用0 时,我得到了几个这样的符号......
        【解决方案8】:

        这个 id 可能不是全局唯一的。 GUID 应该是全局唯一的,因为它们包含不应在其他地方出现的元素(生成 ID 的机器的 MAC 地址、生成 ID 的时间等)

        如果您需要的是在您的应用程序中唯一的 ID,请使用数字喷泉 - 可能将该值编码为十六进制数字。每次需要 id 时,请从数字喷泉中获取。

        如果您有多个服务器分配 id,您可以获取一系列数字(几十或几千,具体取决于您分配 id 的速度),这应该可以完成工作。一个 8 位十六进制数字将为您提供 40 亿个 id - 但您的第一个 id 会短得多。

        【讨论】:

        • 对不起,对于死灵,但什么是数字喷泉?网上没找到定义。它只是一个整数,每次请求新 id 时都会自动递增,还是有一些更深层次的逻辑?
        猜你喜欢
        • 2013-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-06
        • 2016-10-15
        • 2023-03-11
        • 2017-03-25
        • 2021-06-11
        相关资源
        最近更新 更多