代码之家  ›  专栏  ›  技术社区  ›  chakrit Dutchie432

guid/uuid的url压缩表示?

  •  20
  • chakrit Dutchie432  · 技术社区  · 15 年前

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

    现在,不用正常的abcd efgh-…表示法,我使用生成的原始字节,而base64对它们进行编码,这会导致一个略短的字符串。

    但有没有可能把它缩短一点呢?

    我同意失去某种程度的唯一性并保留计数器,但扫描所有现有密钥不是一个选项。建议?

    7 回复  |  直到 7 年前
        1
  •  13
  •   Community CDub    8 年前

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

        2
  •  8
  •   Greg Hewgill    15 年前

    当然,只要用一个大于64的碱基。您将不得不使用自定义字母表对它们进行编码,但您应该能够找到更多“URL安全”的可打印ASCII字符。

    base64使用8对6位进行编码,因此16字节的guid值变为22字节编码。你可以减少一个或两个字符,但不会更多。

        3
  •  2
  •   Meh    15 年前

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

    您还可以缩短guid的长度-例如,使用2个字节指示自2010年以来的天数,使用4个字节表示自当前日期开始以来的毫秒数。在同一毫秒内生成的两个guid只有冲突。您还可以再添加2个随机字节,这样做会更好。

        4
  •  1
  •   Rob    15 年前

    你可以从另一个方向接近它。生成尽可能短的字符串表示形式并将其映射到一个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;
    }
    

    如果保持字符串长度<16,则只需十六进制编码结果并将其传递给guid构造函数进行分析。

        5
  •  1
  •   TJunkie    13 年前

    不是针对完全相同的问题,而是非常接近的问题——我使用了CRC64,base64,得到了11个字节,CRC64已经过测试(还没有被证明)以在广泛的字符串上不产生重复。

    而且,根据定义,它是64位长的,所以您得到的密钥是大小的一半。

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

    或者只需在业务密钥上运行crc64,您就可以拥有一个64位的惟一对象,然后您就可以将它作为base64。

        6
  •  1
  •   Andrei Sura AnhellO    9 年前

    我觉得这个讨论很有趣: 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 |
    +----------------------------------+
    
        7
  •  1
  •   Tom Lobato    7 年前

    (很长一段时间了,但今天又有了同样的需求)

    UUID是128位长,由32个十六进制加4个连字符表示。 如果我们使用64(2^6)个可打印ASCII的字典,那么只需将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
    
    推荐文章