URL-紧凑型GUID / UUID表示?

时间:2010-05-24 19:30:16

标签: guid guid-generation

我需要生成一个GUID并通过字符串表示来保存它。字符串表示应尽可能短,因为它将用作已经很长的URL字符串的一部分。

现在,我没有使用正常的abcd-efgh -...表示,而是使用生成的原始字节和base64编码,这导致字符串更短。

但是可以缩短它吗?

我可以失去一定程度的独特性并保留一个计数器,但扫描所有现有的密钥不是一种选择。建议?

7 个答案:

答案 0 :(得分:13)

我使用Ascii85编码将Guid写入20个ASCII字符的数据库列。我发布了C#代码以防它有用。对于URL编码,特定字符集可能不同,但您可以选择适合您的应用程序的任何字符。它可以在这里找到:What is the most efficient way to encode an arbitrary GUID into readable ASCII (33-127)?

答案 1 :(得分:8)

当然,只需使用大于64的基数。您必须使用自定义字母对其进行编码,但您应该能够找到一些“url-safe”可打印的ASCII字符。

Base64使用8编码6位,因此16字节GUID值变为22字节编码。你可以用一两个字符减少它,但不能多。

答案 2 :(得分:2)

我不确定这是否可行,但您可以将所有生成的GUID放在表中,并在URL中仅使用表中GUID的索引。

您还可以减少guid的长度 - 例如,使用2个字节来表示自2010年以来的天数,以及4个字节表示自当天开始以来的毫秒数。只有在同一毫秒内生成的2个GUID才会发生冲突。你还可以添加2个随机字节,这将使这更好。

答案 3 :(得分:1)

你可以从另一个方向接近这个。生成尽可能短的字符串表示并将其映射到Guid。

使用定义的字母表生成密钥,如下所示:

在伪代码中:

string RandomString(char[] alphabet, int length)
{
  StringBuilder result = new StringBuilder();
  for (int i = 0; i < length; i++)
    result.Append(alphabet[RandomInt(0, alphabet.Length)]);

  return result;
}

如果你保持字符串长度&lt; 16,你可以简单地对结果进行十六进制编码并将其传递给Guid构造函数进行解析。

答案 4 :(得分:1)

我发现这个讨论很有趣:https://www.percona.com/blog/2014/12/19/store-uuid-optimized-way/

基本上,您将36个字符转换为16个字节的二进制文件,但首先使用存储过程对三个时间片进行排序:

set @uuid:= uuid();
select @uuid;
+--------------------------------------+
| @uuid                                |
+--------------------------------------+
| 59f3ac1e-06fe-11e6-ac3c-9b18a7fcf9ed |
+--------------------------------------+

CREATE DEFINER=`root`@`localhost`
    FUNCTION `ordered_uuid`(uuid BINARY(36))
    RETURNS binary(16) DETERMINISTIC
    RETURN UNHEX(CONCAT(SUBSTR(uuid, 15, 4),SUBSTR(uuid, 10, 4),SUBSTR(uuid, 1, 8),SUBSTR(uuid, 20, 4),SUBSTR(uuid, 25)));

select hex(ordered_uuid(@uuid));
+----------------------------------+
| hex(ordered_uuid(@uuid))         |
+----------------------------------+
| 11e606fe59f3ac1eac3c9b18a7fcf9ed |
+----------------------------------+

答案 5 :(得分:1)

(很长一段时间,但今天只是出现了同样的需求)

UUID长度为128位,由32个十六进制加4个连字符表示。 如果我们使用64(2 ^ 6)printtable ascii`s的字典,只需将32位4位(十六进制长度)转换为22位6位组。

这是UUID的缩写。相反,36个字符可以获得22个字符,而不会丢失原始位。

https://gist.github.com/tomlobato/e932818fa7eb989e645f2e64645cf7a5

class UUIDShortner
    IGNORE = '-'
    BASE6_SLAB = ' ' * 22

    # 64 (6 bits) items dictionary
    DICT = 'a'.upto('z').to_a +
        'A'.upto('Z').to_a +
        '0'.upto('9').to_a +
        ['_', '-'] 

    def self.uuid_to_base6 uuid
        uuid_bits = 0

        uuid.each_char do |c|
            next if c == IGNORE
            uuid_bits = (uuid_bits << 4) | c.hex
        end

        base6 = BASE6_SLAB.dup

        base6.size.times { |i|
            base6[i] = DICT[uuid_bits & 0b111111]
            uuid_bits >>= 6
        }

        base6
    end
end

# Examples:

require 'securerandom'
uuid = ARGV[0] || SecureRandom.uuid
short = UUIDShortner.uuid_to_base6 uuid
puts "#{uuid}\n#{short}"

# ruby uuid_to_base6.rb
# c7e6a9e5-1fc6-4d5a-b889-4734e42b9ecc
# m75kKtZrjIRwnz8hLNQ5hd

答案 6 :(得分:0)

不是完全相同的问题,但非常非常接近 - 我使用了CRC64,Base64,你得到11个字节,CRC64已经过测试(未经证实),不能在各种字符串上产生重复。

根据定义它是64位长 - 你得到的密钥是一半大小。

要直接回答原始问题 - 您可以对您的GUID的任何表示进行CRC64编码。

或者只是在业务键上运行CRC64,然后你将拥有64位独特的东西,然后你可以使用base64。