Сжать / urlencode серии из 100 цифр base-4 в JavaScript - PullRequest
1 голос
/ 22 мая 2011

Первое: должно быть сделано полностью в javascript. (JQuery / mootools необязательно)

У меня есть серия из 100 чисел, каждая из которых установлена ​​на 0,1,2 или 3 - они представляют настройки на странице. Я хотел бы закодировать их в максимально короткую строку, чтобы создать постоянную ссылку на страницу.

Я думаю, что лучшим способом было бы хранить их в двоичных куплетах, конвертировать эти куплеты в строку, муравей и затем кодировать строку.

Однако лучшее, что я нашел до сих пор, это parseint( binary_var, 2 ), который охватывает двоичное число в число base_10. Однако, чтобы сделать строку достаточно короткой, мне понадобится лучшая система.

Если бы я мог преобразовать в 64-битную кодировку, я мог бы хранить все данные всего за 4 символа, я думаю. Я знаю, что URL-адреса теперь поддерживают Unicode, и я считаю, что я могу использовать escape и unescape для кодирования / декодирования 64-битных символов, поэтому я ищу основной способ кодировать / декодировать двоичные данные в 64-битные символы.

Конечно, я не уверен на 100%, что это лучший способ или даже сработает, поэтому я совершенно не в курсе, не стесняйтесь указывать мне правильное направление.

Спасибо!

Ответы [ 2 ]

1 голос
/ 22 мая 2011

Вы можете закодировать такие массивы чисел в строку, по 3 на символ, например:

function encodeBase4(base4) {
  var i, rv = [], n = ~~((base4.length + 2) / 3) * 3;

  for (i = 0; i < n; i += 3) {
    rv.push(
      32 +
      ((base4[i] || 0) & 3) +
      ((base4[i + 1] || 0) & 3) * 4 +
      ((base4[i + 2] || 0) & 3) * 16
    );
  }

  return String.fromCharCode.apply(null, rv);
}

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

function decodeBase4(str) {
  var i, rv = [], n = str.length;

  for (i = 0; i < n; ++i) {
    var b = str.charCodeAt(i) - 32;
    rv.push(b & 3);
    rv.push(~~(b / 4) & 3);
    rv.push(~~(b / 16) & 3);
  }

  return rv;
}

Вот jsfiddle , который, кажется, работает в своем простом тестовом примере. (Обратите внимание, что в итоге получается список, кратный 3; вам нужно знать, сколько существует реальных значений, и просто игнорировать нули в конце.)

Теперь эти строки результатов будут «грязными» и требуют кодирования URL, если вы помещаете их в URL. Если вы упаковали только 2 числа на символ, вы можете сделать результирующие строки буквенными и, таким образом, избежать штрафа за кодировку; однако они, конечно, будут длиннее.

0 голосов
/ 22 мая 2011

100 фрагментов информации, каждый из которых содержит 2 бита, требует 200 бит. При кодировании base 64 вам потребуется ceil (200 / log 2 (64)) = 34 символа.

A Сегмент пути URI позволяет 79 символов, которые не требуют кодирования с использованием процентного кодирования. Если вы добавите разделитель сегмента пути /, у вас будет 80 символов и, следовательно, потребуется ceil (200 / log 2 (80)) = 32 символа. Это оптимальное решение, которое вы можете достичь, используя только путь.

Вы можете использовать больше, чем эти символы, даже символы Юникода. Но они должны быть закодированы с использованием процентного кодирования, поскольку URI могут содержать только US-ASCII. Путь URI типа (ä = U + 00E4) на самом деле /%C3%A4, и только браузер отображает его как .


Вот пример (функции взяты из произвольного базового преобразования в javascript ):

function getValueOfDigit(digit, alphabet)
{
   var pos = alphabet.indexOf(digit);
   return pos;
}

function convert(src, srcAlphabet, dstAlphabet)
{
   var srcBase = srcAlphabet.length;
   var dstBase = dstAlphabet.length;

   var wet     = src;
   var val     = 0;
   var mlt     = 1;

   while (wet.length > 0)
   {
     var digit  = wet.charAt(wet.length - 1);
     val       += mlt * getValueOfDigit(digit, srcAlphabet);
     wet        = wet.substring(0, wet.length - 1);
     mlt       *= srcBase;
   }

   wet          = val;
   var ret      = "";

   while (wet >= dstBase)
   {
     var digitVal = wet % dstBase;
     var digit    = dstAlphabet.charAt(digitVal);
     ret          = digit + ret;
     wet /= dstBase;
   }

   var digit    = dstAlphabet.charAt(wet);
   ret          = digit + ret;

   return ret;
}

var base4Alphabet  = "0123",
    base79Alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&'()*+,;=:@",
    base80Alphabet = base79Alphabet+"/";
alert(convert(getValueOfDigit("010203210", base4Alphabet), base4Alphabet, base80Alphabet));  // "C@Q"
...