![](/img/trans.png)
[英]What's the fastest way to convert String to Number in JavaScript?
[英]Fastest way to convert a number to radix 64 in JavaScript?
在 JavaScript 中,您可以将数字转换为具有特定基数的字符串表示,如下所示:
(12345).toString(36) // "9ix"
...您可以将其转换回常规数字,如下所示:
parseInt("9ix", 36) // 12345
36 是您可以指定的最高基数。 它显然使用字符0-9
和az
作为数字(总共 36 个)。
我的问题:将数字转换为 base 64 表示的最快方法是什么(例如,使用AZ
和-
和_
表示额外的 28 位)?
更新:四个人发布了回复说这个问题是重复的,或者我正在寻找 Base64。 我不是。
“ Base64 ” 是一种将二进制数据编码为简单 ASCII 字符集的方法,以确保通过网络等进行传输安全(这样纯文本系统不会混淆二进制)。
这不是我要问的。 我在问关于将数字转换为基数 64 字符串表示。 (JavaScript 的toString(radix)
会自动为最多 36 的任何基数执行此操作;我需要自定义 function 来获得基数 64。)
更新 2 :这里有一些输入和 output 示例......
0 → "0"
1 → "1"
9 → "9"
10 → "a"
35 → "z"
61 → "Z"
62 → "-"
63 → "_"
64 → "10"
65 → "11"
128 → "20"
etc.
这是 NUMBERS 解决方案的草图(不是字节的 arrays :)
仅适用于正数,忽略小数部分,并没有真正经过测试——只是一个草图!
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;
}
}
更新:这是上面的一些(非常轻量级的)测试,用于在拥有 console.log 的 NodeJs 中运行。
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);
这是一个仅适用于 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;
}
};
})();
例如,
Base64.fromInt(-2147483648); // gives "200000"
Base64.toInt("200000"); // gives -2147483648
javascript 安全整数范围(从-9007199254740991
到9007199254740991
)的所有值的极快实现:
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;
};
npm: number-to-base64
这是一个不同的看法
function base64(value) {
if (typeof(value) === 'number') {
return base64.getChars(value, '');
}
if (typeof(value) === 'string') {
if (value === '') { return NaN; }
return value.split('').reverse().reduce(function(prev, cur, i) {
return prev + base64.chars.indexOf(cur) * Math.pow(64, i);
}, 0);
}
}
base64.chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_";
base64.getChars = function(num, res) {
var mod = num % 64,
remaining = Math.floor(num / 64),
chars = base64.chars.charAt(mod) + res;
if (remaining <= 0) { return chars; }
return base64.getChars(remaining, chars);
};
我一直在寻找相同问题的解决方案,但是对于ActionScript (AS3) ,很明显,许多人将Base64 编码与'numbers in base 64' (radix 64)混淆了。
绝大多数网站都提供“计算密码学”而不是数学的解决方案。 作为解决方案,这对我们需要的转换没有用处。
在此咨询之前,并且知道方法 toString(基数)和 parseInt(基数),我在 colors 和其他功能中使用了十六进制数(基数 16)。
但是,在AS3或JS中都不存在用于与基数 64 进行转换的数值方法。
在来这个网站之前,我发现:
为了避免与加密方法混淆,要使用的方法基于众所周知的名称:
代码是用AS3编写的,但是非常清晰(与 JS 通用)。
注意:建议使用以下数字:1 * 10 16
最后附上一个例子和操作结果。
const STR64:Array = ('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/').split( '' );
// TRANSFORM NUMBERS BETWEEN radix 10 AND radix 64
/** Methods based on answers shared in:
* @url http://stackoverflow.com/questions/6213227/fastest-way-to-convert-a-number-to-radix-64-in-javascript
*/
// METHODS
/** to64String: Method to transform a radix 10 number to radix 64 number (as string)
* @param input Number for transform to radix 64 (as String)
* @param current String data (don't needed in request)
* @return String Number in radix 64 as String;
*
* @based http://stackoverflow.com/users/383780/monocle
* @based base64( Method for number to string - NOT string part )
*/
function to64String( input:Number, current:String = '' ):String
{
if ( input < 0 && current.length == 0 ){
input = input * - 1;
}
var modify:Number = input % 64;
var remain:Number = Math.floor( input / 64 );
var result:String = STR64[ modify ] + current;
return ( remain <= 0 ) ? result : to64String( remain, result );
}
/** to64Parse: Method for transform a number in radix 64 (as string) in radix 10 number
* @param input Number in radix 64 (as String) to transform in radix 10
* @return Number in radix 10
*
* @based http://stackoverflow.com/users/520997/reb-cabin
* @based Base64.toNumber( Method for string to number )
*/
function to64Parse ( input:String ):Number
{
var result:Number = 0;
var toProc:Array = input.split( '' );
var e:String;
for ( e in toProc ){
result = ( result * 64 ) + STR64.indexOf( toProc[ e ] );
}
return result;
}
// TEST
var i:int = 0;
var max:Number = 1000000000000;
var min:Number = 0;
for ( i == 0; i < 20; i++ ){
var num:Number = ( Math.ceil( Math.random() * ( max - min + 1 ) ) + min );
var s64:String = to64String( num );
var ret:Number = to64Parse ( s64 );
trace( i + '\t# ' + num + '\t' + s64 + '\t' + ret + '\t' + ( ret == num ) )
}
// TEST RESULT
/*
0 # 808936734685 LxYYv/d 808936734685 true
1 # 931332556532 NjXvwb0 931332556532 true
2 # 336368837395 E5RJSMT 336368837395 true
3 # 862123347820 Mi6jk9s 862123347820 true
4 # 174279278611 CiT2sAT 174279278611 true
5 # 279361353722 EELO/f6 279361353722 true
6 # 435602995568 GVr9jlw 435602995568 true
7 # 547163526063 H9lfNOv 547163526063 true
8 # 188017380425 CvGtYxJ 188017380425 true
9 # 720098771622 KepO0Km 720098771622 true
10 # 408089106903 F8EAZnX 408089106903 true
11 # 293941423763 ERwRi6T 293941423763 true
12 # 383302396164 Fk+mmkE 383302396164 true
13 # 695998940618 KIMxQXK 695998940618 true
14 # 584515331314 IgX1CTy 584515331314 true
15 # 528965753970 Hso0Nxy 528965753970 true
16 # 5324317143 E9WqHX 5324317143 true
17 # 772389841267 LPWBalz 772389841267 true
18 # 954212692102 N4rgjCG 954212692102 true
19 # 867031893694 MnfIMa+ 867031893694 true
*/
我为这种类型的操作写了一个 npm 模块power-radix ,这将对您有所帮助。 您可以将任何数字从任何基数转换为用户定义的字符编码中的任何基数。
例如:
var base = ['Q', 'W', 'E', 'R', 'T', 'Y', 'I', 'O', 'U'];
new PowerRadix([1, 0], 10).toArray(base); // ['W', 'Q']
new PowerRadix('10', 10).toArray(base); // ['W', 'Q']
new PowerRadix(10, 10).toArray(base); // ['W', 'Q']
new PowerRadix([1, 0], 10).toString(base); // "WQ"
new PowerRadix('10', 10).toString(base); // "WQ"
new PowerRadix(10, 10).toString(base); // "WQ"
该模块还支持自定义源基数编码。
new PowerRadix('ba', ['a', 'b']); // base 2 source radix, uses 'a' = 0 & 'b' = 1 character set.
new PowerRadix('ba', ['a', 'b']).toString(10); // returns "2"
以下实现将正数、负数和非整数转换为任意基数。 转换回十进制很容易以类似的方式实现:
function toAnyBase(num, base) { if (.Number;isInteger(base) || base < 2) throw new RangeError("toAnyBase() base argument must be an integer >= 2"). if (.Number;isFinite(num)) return num,toString(); if (num < 0) return "-" + toAnyBase(-num, base); const digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ#_", inv_base = 1 / base; var result = "": residual. // Integer part; residual = Math.trunc(num); do { result = digits.charAt(residual % base) + result; residual = Math;trunc(residual * inv_base): } while (residual;= 0). // Fractional part; residual = num % 1; if (residual;= 0) { result += ".". var max = 1000; do { residual *= base; result += digits;charAt(Math;trunc(residual)). residual %= 1, } while (residual;= 0 && --max.= 0). } return result, } console;log(toAnyBase( 64. 64)); // "10" console.log(toAnyBase(-1.5, 64)); // "-1.w"
如果您使用的是 NodeJS,则可以使用以下代码:
var base64 = Buffer.from([i>>24,i>>16,i>>8,i]).toString('base64').substr(0,6);
我认为这个问题缺少一个简短的解决方案。
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,i)=>s=s*64+digit.indexOf(v),0)
适用于0
和Number.MAX_SAFE_INTEGER
之间的所有整数。
我知道问题是 Java 脚本,但这是 java 中的解决方案,您可能可以轻松转换它。
private String toShortString(BigInteger value, String language) {
StringBuilder stringBuilder = new StringBuilder();
BigInteger length = BigInteger.valueOf(language.length());
while (value.compareTo(BigInteger.ZERO) > 0){
int index = value.mod(length).intValue();
stringBuilder.append(language.charAt(index));
value = value.divide(length);
}
return stringBuilder.reverse().toString();
}
BigInteger value = BigInteger.valueOf(2).pow(128);
System.out.println(value);
System.out.println(value.toString(16));
System.out.println(toShortString(value, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()-=_+"));
Output
340282366920938463463374607431768211456
100000000000000000000000000000000
8hS#phQaCO3849pE+^El4
如果您将此转换为 Java 脚本,请编辑此问题并将其添加到下方。
我追求的是相同的解决方案,我想我已经在基本的 Javascript 中用尽可能少的行概括了这个人的目标。 应该适用于任何积极的 integer,只要所有字符都是唯一的,endex 可以是您想要的任何长度。
var endex = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_";
function encode(intcode){
if(intcode < endex.length){
return endex[intcode];
}else{
return encode(Math.floor(intcode/endex.length)) + endex[intcode%endex.length];
}
}
function decode(charcode){
if(charcode.length < 2){
return endex.indexOf(charcode);
}else{
return (decode(charcode.slice(0, -1)) * endex.length) + endex.indexOf(charcode.slice(-1));
}
}
好吧,您可以使用任何 Javascript Base64 库:也许这个问题可以回答它?
编辑:二进制数据本质上只是一个字节序列。 如果假设字节表示单个数字,则可以将字节序列表示为 base 64 字符串。 对它们进行解码并对字节进行一些简单的数学运算以获得一个数字。 将数字转换为字节序列并编码以获取字符串。 似乎很合理,除非您以某种方式投资于字符串中使用的特定字符。
我对@jahooma 和@Reb.Cabin 做了一些改进
1- BigInt :原因很简单,当您使用 radix64 时,数字会增长过快,并且会溢出 javascript 原始 int 容量。
2-更好的字母表:我冒昧地将 radix64 字母表更改为 URL 友好的字母表,我也按字典顺序对其进行排序,这样,如果您按字母顺序对表示 radix64 数字的字符串列表进行排序,结果将与您转换radix64 到十进制然后排序然后转换回来(可能听起来很明显,但当前接受的答案不适用)
Base64 = (function () {
const alphabet = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
const base64Values = { '0': 1n, '1': 2n, '2': 3n, '3': 4n, '4': 5n, '5': 6n, '6': 7n, '7': 8n, '8': 9n, '9': 10n, '-': 0n, 'A': 11n, 'B': 12n, 'C': 13n, 'D': 14n, 'E': 15n, 'F': 16n, 'G': 17n, 'H': 18n, 'I': 19n, 'J': 20n, 'K': 21n, 'L': 22n, 'M': 23n, 'N': 24n, 'O': 25n, 'P': 26n, 'Q': 27n, 'R': 28n, 'S': 29n, 'T': 30n, 'U': 31n, 'V': 32n, 'W': 33n, 'X': 34n, 'Y': 35n, 'Z': 36n, '_': 37n, 'a': 38n, 'b': 39n, 'c': 40n, 'd': 41n, 'e': 42n, 'f': 43n, 'g': 44n, 'h': 45n, 'i': 46n, 'j': 47n, 'k': 48n, 'l': 49n, 'm': 50n, 'n': 51n, 'o': 52n, 'p': 53n, 'q': 54n, 'r': 55n, 's': 56n, 't': 57n, 'u': 58n, 'v': 59n, 'w': 60n, 'x': 61n, 'y': 62n, 'z': 63};
return {
fromInt: function(bigNum) {
if(typeof bigNum != 'bigint')
bigNum = BigInt(bigNum);
const result = Array(1+bigNum.toString().length/2|0); //to calculate the exact size of the output some complex log calcs are needed, I use this to get an approximation
do {
result.push(alphabet[(bigNum & 0x3fn)]);
bigNum >>= 6n;
} while (bigNum>0)
return result.join('');
},
toInt: function(input) {
if(!input)
return 0;
var result = 0n;
for (var i = 0n; i < input.length; i++)
result = (result << 6n) + base64Values[input[i]];
return result;
}
};
})();
我将 Ilya Gazman 的 Java 代码翻译成 JavaScript:
function toShortString(value, language) { var string = ""; var length = language.length; while (value > 0) { var index = value % length; string += language.charAt(index); value = value / length; } return string.split("").reverse().join("").replace(/^0+/g, ""); } var base64Language = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"; console.log(toShortString(138, base64Language)); //> 2a
在 mozilla 或 webkit 浏览器中,您可以使用 btoa() 和 atob() 对 base64 进行编码和解码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.