сжатие / urlencode серия из 100 чисел с 4 базовыми значениями в javascript

#javascript #url #unicode #encoding #binary

#javascript #url #Юникод #кодирование #двоичный

Вопрос:

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

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

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

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

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

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

Спасибо!

Комментарии:

1. @Tyler — Я не думаю, что файлы cookie будут работать при создании постоянной ссылки…

Ответ №1:

Вы можете закодировать такие массивы чисел в строку, по 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) amp; 3)  
      ((base4[i   1] || 0) amp; 3) * 4  
      ((base4[i   2] || 0) amp; 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 amp; 3);
    rv.push(~~(b / 4) amp; 3);
    rv.push(~~(b / 16) amp; 3);
  }

  return rv;
}
  

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

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

Ответ №2:

для 100 единиц информации по 2 бита каждая требуется в общей сложности 200 бит. При кодировке с основанием 64 вам потребуется ceil (200 / log2(64)) = 34 символа.

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

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


Вот пример (функции, взятые из произвольного преобразования базы в 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-._~!$amp;'()* ,;=:@",
    base80Alphabet = base79Alphabet "/";
alert(convert(getValueOfDigit("010203210", base4Alphabet), base4Alphabet, base80Alphabet));  // "C@Q"
  

Комментарии:

1. С кодировкой base64 вы можете поместить 3 значения на байт, нет? А лог с основанием 2 из 64 равен 6, поэтому ответ состоит из 34 символов, а не из 70…

2. @Pointy: Да, log_2(64) = 6 бит и 6 бит / 2 бита / символ = 3 символа.

3. хм… да? Я хочу сказать, что список из 100 значений 2-разрядных чисел может быть сохранен в 34 символах, поскольку каждый содержит (до) трех значений.

4. Ничего страшного, в конце концов, сегодня выходные 🙂