#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. Ничего страшного, в конце концов, сегодня выходные 🙂