【问题标题】:How to shorten the number of bits to represent a character sequence如何缩短表示字符序列的位数
【发布时间】:2019-12-09 07:06:01
【问题描述】:

假设我想存储一个长度为 64 个字符的 ID,它会从一组 n 字符中选择其字符(例如,在此示例中为 26 小写字符,但可以是任何数字 n)。问题是(a)我可以编码的最短位 b 是多少,以及(b)我如何使用该位数 b 来处理任何长度为 n 的字符序列。具体来说,如果我有一个 26 个字符的字母表 (n),并且我想要一个 64 个字符长的字符串 (m),你可以将它压缩成多少位?假设集合26^64 中可能有任何字符序列。更一般地说,在集合n^m 中,可以采取什么方法来缩小表示该数字所需的位数?我在想象像VLQ 这样的魔法。在这个问题中,我更喜欢让每个数字都使用相同位数的方法,但在以后的问题中,我可能会修改这个问题并根据数字使编码成为任意长度。但是对于这个问题,任何由字母表 a-z 组成的 64 字符 ID,您可以将其编码多短以便每个缩短的字符串/位序列都是相同的位数

例如:

abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd

a-z 集合中的 64 个字符。我可以将其编码为:

16abcd

它的意思是16 x abcd。但这仅适用于重复的 4 字符序列。 (只是一个快速编造的例子)。对于任意序列,例如:

wckdrwncwkdcwjdncjdjwcjwjncdjwwckdrwncwkdcwjdncjdjwcjwjncdjwkwlp

如何将其缩短为更少的位数?这样每个 64 个字符的序列都会缩短到相同的位数。如果有帮助,假设要从中选择字符的字母 比 ID 的字符大小(在本例中为 64)。但是很高兴知道如何为比序列长的字符集执行此操作(所以 52 个字符的字母,长度为 16 个字符,键入东西)。理想情况下,解释会使用 JavaScript 或类似的东西来演示:) 我不知道该怎么做。

【问题讨论】:

  • 64 个小写字符可以转换为适合 38 个字节(每次),这是您的意思吗?这只是一个基本的转换
  • 我不确定,我得看看,听起来好像可以!

标签: javascript string bit-manipulation


【解决方案1】:

如果您不介意通过 BigInt(避免它很棘手,但可能),可以这样做:

function convert(s) {
    console.assert(s.length == 64);
    // convert the string to a BigInt
    var val = 0n;
    for (var i = 0; i < 64; i++)
        val = val * 26n + BigInt(s.charCodeAt(i) - 0x61);
    // convert the BigInt to bytes
    var bytes = new Uint8Array(38);
    for (var i = 0; i < 38; i++) {
        bytes[i] = Number(val & 0xFFn);
        val >>= 8n;
    }
    return bytes;
}

本质上,这会将字符串解析为 base-26 数字(按正常顺序),然​​后将其分解为 base-256 数字(最低有效字节在前)。比如:

convert("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") =
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
convert("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab") =
    [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
...
convert("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzy") =
    [254, 255, 255, 255, 255, 255, 255, 255, 0, 241, 228, 56, 161, 115, 35, 152, 36, 64, 88, 48, 43, 115, 134, 63, 100, 222, 5, 194, 138, 113, 20, 60, 164, 54, 17, 7, 104, 28]
convert("zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz") =
    [255, 255, 255, 255, 255, 255, 255, 255, 0, 241, 228, 56, 161, 115, 35, 152, 36, 64, 88, 48, 43, 115, 134, 63, 100, 222, 5, 194, 138, 113, 20, 60, 164, 54, 17, 7, 104, 28]

【讨论】:

  • @LancePollard 你已经走对了,对吧?您提到了 26^64 和 n^m,完全正确。下一步是,字符序列不只是来自那个大小的集合,它们从 1 到 1 映射到 0 到 n^m (不包括)范围内的整数,转换它们的方法只是解析以 n 为底的数字(您知道如何解析以 10 为底的数字,对吗?然后将 10 替换为 n)。然后转换为 base-256 与将数字转换为十进制字符串的处理方式相同,但再次将 10 替换为 256(我将模数替换为按位与,除法替换为右移,这样更好)
  • 我的意思是你是怎么学到这么多关于这些主题的,这是一个很难的领域!
  • 也感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2014-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-25
  • 1970-01-01
  • 1970-01-01
  • 2017-11-11
相关资源
最近更新 更多