Подтвердить что ты не робот

Самый быстрый способ конвертировать число в radix 64 в JavaScript?

В JavaScript вы можете преобразовать число в строковое представление с определенным radix следующим образом:

(12345).toString(36) // "9ix"

... и вы можете преобразовать его обратно в обычное число следующим образом:

parseInt("9ix", 36) // 12345

36 - наивысшее значение, которое вы можете указать. Он явно использует символы 0-9 и a-z для цифр (всего 36).

Мой вопрос: какой самый быстрый способ преобразовать число в представление базы 64 (например, используя a-z и - и _ для дополнительных 28 цифр)?


Обновить. Четыре человека опубликовали ответы, в которых говорится, что этот вопрос дублируется или что я ищу Base64. Я не.

"Base64" - это способ кодирования двоичных данных в простом наборе символов ASCII, чтобы сделать его безопасным для передачи по сетям и т.д. (так что текст - только системы не будут искажать двоичные файлы).

Это не то, о чем я прошу. Я прошу преобразовать числа в строковое представление radix 64. (JavaScript toString(radix) делает это автоматически для любого radix до 36, мне нужна настраиваемая функция для получения radix 64.)


Обновление 2. Вот несколько примеров ввода и вывода...

0   → "0"
1   → "1"
9   → "9"
10  → "a"
35  → "z"
61  → "Z"
62  → "-"
63  → "_"
64  → "10"
65  → "11"
128 → "20"
etc.
4b9b3361

Ответ 1

Вот эскиз для решения для 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;
    }
}

UPDATE: здесь некоторые (очень легкие) тесты выше, для запуска в NodeJ, где у вас есть console.log.

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);

Ответ 2

Здесь версия для 32-битных ints, то есть любое число между -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

Ответ 3

Я искал решение той же проблемы, но для ActionScript (AS3), и было очевидно, что многие люди путают кодировку Base64 с 'номерами в базе 64' (radix 64).

Подавляющее большинство сайтов предлагают решения для "вычислительной криптографии" и не математики. В качестве решений это не полезно для необходимого преобразования.

До этой консультации и знал методы toString (radix) и parseInt (radix), я работал с шестнадцатеричными числами (radix 16) в обоих цветах и ​​другими функциями.

Однако ни в AS3, ни в JS не существует числового метода для преобразования в и из radix 64.

До прихода на этот сайт я нашел:

  • В различных онлайн-калькуляторах radix 64 не начинается с нуля, но A.
    Например: convertix.com и alfredo4570.net
  • В radix 64 формируются следующие наборы упорядоченных символы: AZ, az, 0-9, + и/(это я определил константу: 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
*/

Ответ 4

Я написал модуль 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"

Ответ 5

Если вы используете NodeJS, вы можете использовать следующий код:

var base64 = Buffer.from([i>>24,i>>16,i>>8,i]).toString('base64').substr(0,6);

Ответ 6

Здесь другое взятие

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);
};

Ответ 7

Я знаю, что вопрос в Java Script, но вот решение в 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, "[email protected]#$%^&*()-=_+"));

Выход

340282366920938463463374607431768211456
100000000000000000000000000000000
8hS # phQaCO3849pE + ^ El4

Если вы конвертируете это в Java Script, отредактируйте этот вопрос и добавьте его ниже.

Ответ 8

Следующая реализация преобразует положительные, отрицательные и нецелые числа в произвольную базу. Преобразование обратно в десятичное легко реализуется аналогичным образом:

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"

Ответ 9

Ну, вы можете просто использовать любую библиотеку JavaScript JavaScript: возможно, этот вопрос отвечает на него?

EDIT: двоичные данные - это всего лишь последовательность байтов. Если вы считаете, что байты представляют собой один номер, вы можете представить последовательность байтов в качестве базовой 64-строки. Дефрагментируйте их и проделайте некоторую тривиальную математику по байтам, чтобы получить число. Преобразуйте число в последовательность байтов и закодируйте, чтобы получить строку. Кажется вполне разумным, если вы каким-то образом не инвестировали в конкретные символы, используемые в String.

Ответ 10

В браузере mozilla или webkit вы можете использовать btoa() и atob() для кодирования и декодирования base64.