在javascript中压缩/ urlencode一系列100个base-4数字

时间:2011-05-21 20:44:20

标签: javascript url unicode encoding binary

第一件事:必须完全用javascript完成。 (JQuery / mootools可选)

我有一系列100个数字,每个数字设置为0,1,2或3 - 这些代表页面上的设置。我想将这些编码为最短的字符串,以创建页面的永久链接。

我认为最好的方法是将它们存储在二进制对联中,将这些对偶转换为字符串,然后对该字符串进行urlencode。

然而,到目前为止我发现的最好的是parseint( binary_var, 2 ),它将二进制数转换为base_10数。但是为了让字符串足够短,我需要一个更好的系统。

如果我可以转换为64位编码,我认为我可以将所有数据存储在4个字符中。我知道网址现在支持unicode,我相信我可以使用escapeunescape来编码/解码64位字符,所以我要找的主要方法是编码/解码二进制数据到64位字符。

当然,我不是百分百肯定这是最好的方式,或者甚至会工作,所以我完全偏离轨道随意指出我正确的方向。

谢谢!

2 个答案:

答案 0 :(得分: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) & 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;
}

这里的the jsfiddle似乎适用于其简单的测试用例。 (请注意,您最终会得到一个长度为3的倍数的列表;您必须知道有多少实数值,并且最后忽略零。)

现在这些结果字符串将“脏”并且如果您将它们放入URL中则需要URL编码。如果每个字符只打包2个数字,则可以使得结果字符串全部为字母,从而避免编码惩罚;但是,当然,它们会更长。

答案 1 :(得分:0)

每条2比特的100条信息总共需要200比特。使用base 64编码,你需要ceil(200 / log 2 (64))= 34个字符。

URI path segment允许79个字符不需要使用百分比编码进行编码。如果添加路径段分隔符/,则有80个字符,因此需要ceil(200 / log 2 (80))= 32个字符。这是单独使用路径可以达到的最佳效果。

您可以使用多个字符,甚至是Unicode字符。但是那些需要使用百分比编码进行编码,因为URI只允许包含US-ASCII。像ä = U + 00E4)这样的URI路径实际上是/%C3%A4,只有浏览器会将其显示为


以下是一个示例(从arbitrary base conversion in 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"