在JavaScript中将数字转换为基数为64的最快方法?

cal*_*lum 56 javascript

在JavaScript中,您可以将数字转换为具有特定基数的字符串表示,如下所示:

(12345).toString(36) // "9ix"
Run Code Online (Sandbox Code Playgroud)

...你可以将它转换回这样的常规数字:

parseInt("9ix", 36) // 12345
Run Code Online (Sandbox Code Playgroud)

36是您可以指定的最高基数.它显然使用了字符0-9a-z数字(总共36个).

我的问题:什么是一个数字转换为基64表示以最快的方式(例如,使用A-Z,并-_对额外的28位数字)?


更新:有四个人发布了回复,说这个问题是重复的,或者我正在寻找Base64.我不是.

" Base64 "是一种在简单的ASCII字符集中编码二进制数据的方法,使其可以安全地通过网络等传输(因此纯文本系统不会使二进制文件乱码).

那不是我要问的.我问的是将数字转换为基数64字符串表示.(JavaScript toString(radix)会自动为任何高达36的基数执行此操作;我需要一个自定义函数来获取基数64.)


更新2:以下是一些输入和输出示例......

0   ? "0"
1   ? "1"
9   ? "9"
10  ? "a"
35  ? "z"
61  ? "Z"
62  ? "-"
63  ? "_"
64  ? "10"
65  ? "11"
128 ? "20"
etc.
Run Code Online (Sandbox Code Playgroud)

Reb*_*bin 47

这是一个NUMBERS解决方案的草图(不是字节数组:)

只有正数,忽略小数部分,而不是真正测试 - 只是草图!

Base64 = {

    _Rixits :
//   0       8       16      24      32      40      48      56     63
//   v       v       v       v       v       v       v       v      v
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/",
    // You have the freedom, here, to choose the glyphs you want for 
    // representing your base-64 numbers. The ASCII encoding guys usually
    // choose a set of glyphs beginning with ABCD..., but, looking at
    // your update #2, I deduce that you want glyphs beginning with 
    // 0123..., which is a fine choice and aligns the first ten numbers
    // in base 64 with the first ten numbers in decimal.

    // This cannot handle negative numbers and only works on the 
    //     integer part, discarding the fractional part.
    // Doing better means deciding on whether you're just representing
    // the subset of javascript numbers of twos-complement 32-bit integers 
    // or going with base-64 representations for the bit pattern of the
    // underlying IEEE floating-point number, or representing the mantissae
    // and exponents separately, or some other possibility. For now, bail
    fromNumber : function(number) {
        if (isNaN(Number(number)) || number === null ||
            number === Number.POSITIVE_INFINITY)
            throw "The input is not valid";
        if (number < 0)
            throw "Can't represent negative numbers now";

        var rixit; // like 'digit', only in some non-decimal radix 
        var residual = Math.floor(number);
        var result = '';
        while (true) {
            rixit = residual % 64
            // console.log("rixit : " + rixit);
            // console.log("result before : " + result);
            result = this._Rixits.charAt(rixit) + result;
            // console.log("result after : " + result);
            // console.log("residual before : " + residual);
            residual = Math.floor(residual / 64);
            // console.log("residual after : " + residual);

            if (residual == 0)
                break;
            }
        return result;
    },

    toNumber : function(rixits) {
        var result = 0;
        // console.log("rixits : " + rixits);
        // console.log("rixits.split('') : " + rixits.split(''));
        rixits = rixits.split('');
        for (var e = 0; e < rixits.length; e++) {
            // console.log("_Rixits.indexOf(" + rixits[e] + ") : " + 
                // this._Rixits.indexOf(rixits[e]));
            // console.log("result before : " + result);
            result = (result * 64) + this._Rixits.indexOf(rixits[e]);
            // console.log("result after : " + result);
        }
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

更新:这是上面的一些(非常轻量级)测试,用于在您拥有console.log的NodeJ中运行.

function testBase64(x) {
    console.log("My number is " + x);
    var g = Base64.fromNumber(x);
    console.log("My base-64 representation is " + g);
    var h = Base64.toNumber(g);
    console.log("Returning from base-64, I get " + h);
    if (h !== Math.floor(x))
        throw "TEST FAILED";
}

testBase64(0);
try {
    testBase64(-1);
    }
catch (err) {
    console.log("caught >>>>>>  " + err);
    }
try {
    testBase64(undefined);
    }
catch (err) {
    console.log("caught >>>>>>  " + err);
    }
try {
    testBase64(null);
    }
catch (err) {
    console.log("caught >>>>>>  " + err);
    }
try {
    testBase64(Number.NaN);
    }
catch (err) {
    console.log("caught >>>>>>  " + err);
    }
try {
    testBase64(Number.POSITIVE_INFINITY);
    }
catch (err) {
    console.log("caught >>>>>>  " + err);
    }
try {
    testBase64(Number.NEGATIVE_INFINITY);
    }
catch (err) {
    console.log("caught >>>>>>  " + err);
    }

for(i=0; i<100; i++)
    testBase64(Math.random()*1e14);
Run Code Online (Sandbox Code Playgroud)


jah*_*oma 15

这是一个仅适用于32位整数的版本,即-2147483648和2147483647(含)之间的任何数字.

我在Reb Cabin的顶部答案中修改了版本.这应该快得多,因为它使用位操作和查找表.

Base64 = (function () {
    var digitsStr = 
    //   0       8       16      24      32      40      48      56     63
    //   v       v       v       v       v       v       v       v      v
        "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-";
    var digits = digitsStr.split('');
    var digitsMap = {};
    for (var i = 0; i < digits.length; i++) {
        digitsMap[digits[i]] = i;
    }
    return {
        fromInt: function(int32) {
            var result = '';
            while (true) {
                result = digits[int32 & 0x3f] + result;
                int32 >>>= 6;
                if (int32 === 0)
                    break;
            }
            return result;
        },
        toInt: function(digitsStr) {
            var result = 0;
            var digits = digitsStr.split('');
            for (var i = 0; i < digits.length; i++) {
                result = (result << 6) + digitsMap[digits[i]];
            }
            return result;
        }
    };
})();
Run Code Online (Sandbox Code Playgroud)

例如,

Base64.fromInt(-2147483648); // gives "200000"
Base64.toInt("200000"); // gives -2147483648
Run Code Online (Sandbox Code Playgroud)


Nej*_*sek 12

我认为这个问题缺少一个简短的解决方案。

const digit="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_";
toB64=x=>x.toString(2).split(/(?=(?:.{6})+(?!.))/g).map(v=>digit[parseInt(v,2)]).join("")
fromB64=x=>x.split("").reduce((s,v)=>s*64+digit.indexOf(v),0)
Run Code Online (Sandbox Code Playgroud)

适用于0和之间的所有整数Number.MAX_SAFE_INTEGER

  • +1。如果您使用“-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz”,则“toB64”的输出将按字典顺序排列。 (3认同)

kut*_*luk 6

极其快速地实现 JavaScript 安全整数范围的所有值(从-90071992547409919007199254740991):

const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

// binary to string lookup table
const b2s = alphabet.split('');

// string to binary lookup table
// 123 == 'z'.charCodeAt(0) + 1
const s2b = new Array(123);
for (let i = 0; i < alphabet.length; i++) {
  s2b[alphabet.charCodeAt(i)] = i;
}

// number to base64
const ntob = (number) => {
  if (number < 0) return `-${ntob(-number)}`;

  let lo = number >>> 0;
  let hi = (number / 4294967296) >>> 0;

  let right = '';
  while (hi > 0) {
    right = b2s[0x3f & lo] + right;
    lo >>>= 6;
    lo |= (0x3f & hi) << 26;
    hi >>>= 6;
  }

  let left = '';
  do {
    left = b2s[0x3f & lo] + left;
    lo >>>= 6;
  } while (lo > 0);

  return left + right;
};

// base64 to number
const bton = (base64) => {
  let number = 0;
  const sign = base64.charAt(0) === '-' ? 1 : 0;

  for (let i = sign; i < base64.length; i++) {
    number = number * 64 + s2b[base64.charCodeAt(i)];
  }

  return sign ? -number : number;
};
Run Code Online (Sandbox Code Playgroud)

npm:数字转base64

性能比较:https://jsperf.com/number-to-base64-encoding

  • 我认为这是最好的实现! (2认同)