algorithm - 将数字列表压缩或编码为单个字母数字字符串的最佳方法是什么?

标签 algorithm string encoding

将任意长度和大小的数字列表压缩或编码为单个字母数字字符串的最佳方法是什么?

目标是能够将类似 1,5,8,3,20,212,42 的内容转换为类似 a8D1jN 的内容以在 URL 中使用,然后再转换回 1,5,8,3,20,212,42 .

对于生成的字符串,我可以使用任何数字和任何 ASCII 字母,小写和大写,所以:0-9a-zA-Z。我不希望有任何标点符号。

最佳答案

如果您将列表视为一个字符串,那么您有 11 个不同的字符需要编码(0-9 和逗号)。这可以用 4 位表示。如果您愿意添加,请说 $ 和 !到您的可接受字符列表,那么您将有 64 个不同的输出字符,因此能够对每个字符编码 6 位。

这意味着您可以将字符串映射到比原始字符串短约 30% 的编码字符串,并且相当模糊且看起来随机。

这样您就可以将数字系列 [1,5,8,3,20,212,42] 转码为字符串“gLQfoIcIeQqq”。

更新:我受到启发并为此解决方案编写了一个 python 解决方案(速度不快但功能足够......)

    ZERO = ord('0')
    OUTPUT_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789$!"

    def encode(numberlist):

        # convert to string -> '1,5,8,3,20,212,42'
        s = str(numberlist).replace(' ','')[1:-1]

        # convert to four bit values -> ['0010', '1011', '0110', ... ]
        # (add 1 to avoid the '0000' series used for padding later)
        four_bit_ints = [0 <= (ord(ch) - ZERO) <= 9 and (ord(ch) - ZERO) + 1 or 11 for ch in s]
        four_bits = [bin(x).lstrip('-0b').zfill(4) for x in four_bit_ints]

        # make binary string and pad with 0 to align to 6 -> '00101011011010111001101101...'
        bin_str = "".join(four_bits)
        bin_str = bin_str + '0' * (6 - len(bin_str) % 6)

        # split to 6bit blocks and map those to ints
        six_bits = [bin_str[x * 6 : x * 6 + 6] for x in range(0, len(bin_str) / 6)]
        six_bit_ints = [int(x, 2) for x in six_bits]

        # map the 6bit integers to characters
        output = "".join([OUTPUT_CHARACTERS[x] for x in six_bit_ints])

        return output

    def decode(input_str):

        # map the input string from characters to 6bit integers, and convert those to bitstrings
        six_bit_ints = [OUTPUT_CHARACTERS.index(x) for x in input_str]
        six_bits = [bin(x).lstrip('-0b').zfill(6) for x in six_bit_ints]

        # join to a single binarystring
        bin_str = "".join(six_bits)

        # split to four bits groups, and convert those to integers
        four_bits = [bin_str[x * 4 : x * 4 + 4] for x in range(0, len(bin_str) / 4)]
        four_bit_ints = [int(x, 2) for x in four_bits]

        # filter out 0 values (padding)
        four_bit_ints = [x for x in four_bit_ints if x > 0]

        # convert back to the original characters -> '1',',','5',',','8',',','3',',','2','0',',','2','1','2',',','4','2'
        chars = [x < 11 and str(x - 1) or ',' for x in four_bit_ints]

        # join, split on ',' convert to int
        output = [int(x) for x in "".join(chars).split(',') if x]

        return output


    if __name__ == "__main__":

        # test
        for i in range(100):
            numbers = range(i)
            out = decode(encode(numbers))
            assert out == numbers

        # test with original series
        numbers = [1,5,8,3,20,212,42]
        encoded = encode(numbers)
        print encoded         # prints 'k2UBsZgZi7uW'
        print decode(encoded) # prints [1, 5, 8, 3, 20, 212, 42]


关于algorithm - 将数字列表压缩或编码为单个字母数字字符串的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3858245/

相关文章:

algorithm - 文本编辑器中的前 3 个字数

php - PHP int(0) 的字符串求值

java - 用特殊符号分割字符串并将特殊符号包含到第一个子字符串后,如何从字符串中获取子字符串?

Javascript 解码 =C3=B3 引用可打印

python - PIL/Pillow 解码 icc 配置文件信息

c# - WebBrowser 保持 url/uri 编码不解码

java - 如何快速恢复随机交换 2 个元素的递增数组?

algorithm - 什么是尾调用优化?

java - 记录器级别算法

java - 如何使用 Java 正确转义 awk 输入的字符串?