JavaScript에서 숫자를 기수 64로 변환하는 가장 빠른 방법은 무엇입니까?
JavaScript 에서 다음과 같이 특정 기수 를 사용하여 숫자를 문자열 표현으로 변환 할 수 있습니다 .
(12345).toString(36) // "9ix"
... 다음과 같은 일반 숫자로 다시 변환 할 수 있습니다.
parseInt("9ix", 36) // 12345
36은 지정할 수있는 가장 높은 기수입니다. 분명히 문자 0-9
와 a-z
숫자 (총 36 개)를 사용합니다.
내 질문 : 무엇 기본 64 표현으로 숫자를 변환하는 가장 빠른 방법 (예를 들어, 사용,의 A-Z
, 그리고 -
및 _
추가 28 자리의 경우)?
업데이트 : 4 명이이 질문이 중복되었거나 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.
다음은 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;
}
}
업데이트 : 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);
다음은 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
다른 테이크가 있습니다.
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 인코딩 을 'base 64의 숫자'(radix 64) 와 혼동하는 것이 분명했습니다 .
사이트의 대부분은 솔루션 제공 '전산 암호' 와 하지 수학을 . 해결책으로서 이것은 우리가 필요한 변환에 유용하지 않습니다.
이 상담 이전에 toString (기수) 및 parseInt (기수) 메소드를 알고 있었기 때문에 색상과 다른 기능 모두에서 16 진수 (기수 16)로 작업했습니다.
그러나 AS3 또는 JS 에는 기수 64로 (부터) 변환을위한 수치 적 방법이 없습니다.
이 사이트에 오기 전에 다음을 발견했습니다.
- 다양한 온라인 계산기에서 64 기수 처음부터 시작,하지만 . 예 : convertix.com 및 alfredo4570.net
- 에서는 기수 64 AZ, AZ, 0-9 + 및 / (I 이러한 상수를 정의 : STR64)를 지시 문자의 다음 세트에 의해 형성된다
암호화 방법과의 혼동을 피하기 위해 사용되는 방법은 잘 알려진 이름을 기반으로합니다.
- toString / to64String
- parseInt / to64Parse
코드는 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
*/
자바 스크립트 안전 정수 범위의 모든 값에 대한 매우 빠른 구현 ( -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
성능 비교 : https://jsperf.com/number-to-base64-encoding
이 유형의 작업을위한 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"
The following implementation converts positive, negative and non-integer numbers to an arbitrary base. The conversion back to decimal is easily implemented in a similar fashion:
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"
If you are using NodeJS, you can use the following code:
var base64 = Buffer.from([i>>24,i>>16,i>>8,i]).toString('base64').substr(0,6);
Well, you could just use any Javascript Base64 library: perhaps this question answers it?
EDIT: Binary data is essentially just a sequence of bytes. If you assume the bytes represent a single number you can represent the sequence of bytes as a base 64 string. Decode them and do some trivial math on the bytes to get a number. Convert the number to a sequence of bytes and encode to get a string. Seems quite reasonable, unless you are somehow invested in the specific characters used in the String.
I know the question is Java Script, but here is a solution in java, you probably can easily convert it.
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();
}
Usage
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
If you convert this to Java Script please edit this question and add it below.
In a mozilla or webkit browser you can use btoa() and atob() to encode and decode base64.
ReferenceURL : https://stackoverflow.com/questions/6213227/fastest-way-to-convert-a-number-to-radix-64-in-javascript
'developer tip' 카테고리의 다른 글
간단한 직렬 지점 간 통신 프로토콜 (0) | 2021.01.08 |
---|---|
비동기 작업에 http 상태 202 사용 (0) | 2021.01.08 |
Spring Security의 다중 인증 공급자 (0) | 2021.01.08 |
cURL 오류 (7) 해결 방법 : 호스트에 연결할 수 없습니까? (0) | 2021.01.08 |
로거에 대한 핸들러를 찾을 수 없습니다. (0) | 2021.01.07 |