如何从 JavaScript 中特定位数的一组整数生成固定长度的代码

How to generate a fixed-length code from a set of integers of a specific bit count in JavaScript

收到以下答复:

function parseInt(value, code) {
    return [...value].reduce((r, a) => r * code.length + code.indexOf(a), 0);
}

function toString(value, code) {
    var digit,
        radix= code.length,
        result = '';

    do {
        digit = value % radix;
        result = code[digit] + result;
        value = Math.floor(value / radix);
    } while (value)

    return result;
}

console.log(parseInt('dj', 'abcdefghijklmnopqrstuvwxyz0123456789+-'));
console.log(toString(123, 'abcdefghijklmnopqrstuvwxyz0123456789+-'));
console.log(parseInt('a', 'abcdefghijklmnopqrstuvwxyz0123456789+-'));
console.log(toString(0, 'abcdefghijklmnopqrstuvwxyz0123456789+-'));

我对稍微不同的东西感兴趣。虽然这将生成数字的最短代码,但我现在想根据 的数量生成一个恒定长度的代码。我不确定这是否也是一个复杂的基数解决方案。

假设我想使用 16 个字符的字母表生成 8 位代码。这意味着我应该能够将前 4 位取到 select 1 个字符,然后将接下来的 4 位取到 select 第二个字符。所以如果我的 16 个字符集是 ABDHNMOPQRSTUVYZ,我可能会得到 MV。同样,如果我有一个 16 位范围,我将有 4 个字符代码,而 32 位范围将是一个 8 个字符代码。所以调用 code32(1, 'ABDHNMOPQRSTUVYZ') 会给出一个 8 个字母的代码,而 code8(1, 'ABDHNMOPQRSTUVYZ') 会给出一个 2 位数的代码。

如何在 JavaScript 中实施?类似的东西?

 code8(i, alpha) // 0 to 255 it accepts
 code16(i, alpha) // 0 to 65535 it accepts
 code32(i, alpha) // 0 to 2^32-1 it accepts

同样,如何将字符串代码恢复为原始数字(或位序列)?

编辑:我刚刚注意到您还需要一个解码器。实现非最优版本也很容易,而最优版本可以通过遍历每个字母并累加它们的值乘以它们的权重来实现。

这是你想要的吗?我针对 bit=16bit=8 测试了此代码,但是当 bit=32 代码字数变得太大并挂起浏览器的 devtools。只是演示代码,实际使用中可能需要优化...

function genCode(len, alpha){
    let tmp = [...alpha];
    for(let i = 1; i != len; ++i){
        const ttmp = [];
        tmp.forEach(te => {
            [...alpha].forEach(e => {
                ttmp.push(te + e);
            });
        });
        tmp = ttmp;
    }
    return tmp;
}

function code(bits, i, alpha){
    const len = Math.ceil(bits / Math.floor(Math.log2(alpha.length)));
    return genCode(len, alpha)[i];
}  

function decode(bits, c, alpha){
    const len = Math.ceil(bits / Math.floor(Math.log2(alpha.length)));
    const codes = genCode(len, alpha);
    return codes.indexOf(c);
}

console.log(code(16, 2, "ABDHNMOPQRSTUVYZ"));
console.log(decode(16, "AAAD", "ABDHNMOPQRSTUVYZ"));
console.log(code(8, 255, "ABDHNMOPQRSTUVYZ"));
console.log(decode(8, "ZZ", "ABDHNMOPQRSTUVYZ"));

这实际上归结为改变 toString 以便:

  • 它只接受长度为2的幂的代码
  • 它将结果填充到给定数量的“数字”(字符)

16 位数的实际位数取决于代码的大小。如果代码有 16 个字符,那么它可以覆盖 4 个位,因此需要 4 个字符的输出。但是,如果代码有 4 个字符,则输出将需要 8 个字符。您可能会遇到匹配不准确的情况,例如当您有一个包含 8 个字符的代码时。然后输出将需要 6 个字符。

这里我强调了 toString 方法的变化。我个人的偏好是也将值作为 last 参数放入 toString.

function toString(digitCount, code, value) { // <-- add argument digitCount
    // Perform a sanity check: code must have a length that is power of 2
    if (Math.log2(code.length) % 1) throw "code size not power of 2: " + code.length;
    var digit,
        radix = code.length,
        result = '';

    do {
        digit = value % radix;
        result = code[digit] + result;
        value = Math.floor(value / radix);
    } while (value)

    return result.padStart(digitCount, code[0]); // Pad to the desired output size
}

console.log(toString(4, 'abcdefghijklmnop',    123));
console.log(toString(4, 'abcdefghijklmnop',      0));
console.log(toString(4, 'abcdefghijklmnop', 0xFFFF));

// You could define some more specific functions

const code8 = (code, value) => toString(Math.ceil(8 / Math.log2(code.length)), code, value);
const code16 = (code, value) => toString(Math.ceil(16 / Math.log2(code.length)), code, value);  

console.log(code16('abcdefghijklmnop',    123));
console.log(code16('abcdefghijklmnop',      0));
console.log(code16('abcdefghijklmnop', 0xFFFF));

console.log(code8('abcdefghijklmnop',  123));
console.log(code8('abcdefghijklmnop',    0));
console.log(code8('abcdefghijklmnop', 0xFF));