有没有一种方法可以将一个由250多个1和0组成的JavaScript数组压缩成更易处理的东西(比如较短的字符串),然后再解压缩回来?就像Google对图像编码的方式一样...
谢谢!
谢谢!
base 32, 50 chars: 250|qgl6alf1q2lbl1aclau3k5ana2kpals78alek59ilboeglajgu
base 16, 63 chars: 250|D42A6555E1D0AABA854CAABC3A155750A995578742AAEA1532AAF0E85553878
function bitstringEncode(bitstring) {
var i, l = bitstring.length,
retval = l.toString() + '|';
for (i = 0; i < l; i += 5) {
retval += parseInt((bitstring.substr(i, 5) + '0000').substr(0, 5), 2).toString(32);
}
return retval;
}
这个函数会向最近的5位进行填充,可能会在你提供的长度末尾生成一个虚假的额外字符。我还包括了每个转换函数的第二个版本,它们会填充到最近的10位,可能会生成多达两个虚假的额外字符。我包含它们是因为如果速度很重要,它们可能(也可能不)更快,因为它们从输入中获取更大的块。
parseInt(string, radix)
方法,可以将以基数 radix
写入的数字字符串值 string
转换为 Number
类型的值,还有一个 number.toString(radix)
方法,可以将 Number
值 number
转换为以基数 radix
写入的数字字符串。Number
类型是IEEE-754双精度浮点数实现,因此存在多个整数精度限制。据我所知,其中之一是对于一个全为1的比特数组,除非您的数组不包含超过53个比特元素(或者您的字符串不包含超过53个“1”),否则您无法在不失去精度的情况下将整个比特串来回转换。(IEEE-754双精度的有效数字具有53位精度。)0
的信息都会丢失。因此,在从转换结果恢复位流时,您需要在每个块的左侧填充零,以使每个解码块与原始块一样长。块大小需要权衡编码流所需的步骤数以及解码它时需要填充的零的数量。11|001|001
- 3|1|1 - 和左边界的110|010|01
- 6|2|1
-,两者都具有块大小3)。首先对数据进行编码的原因是为了生成一个短的URI。因此,在编码之前应该从右到左处理流。(这种方法还消除了在编码的字符串中包含原始位数的必要性,如果该数字是块大小的倍数。)/*
* @param bitArray : Array[Number|String]
* @param chunkSize : optional Number = 53
* @param chunkBase: optional Number = 36
* @param delim : optional String = ","
* Delimiter to use.
* @return string
*/
function bitEncode (bitArray, chunkSize, chunkBase, delim)
{
var chunkArray = [];
if (!chunkSize || chunkSize < 2 || chunkSize > 53)
{
chunkSize = 53;
}
if (!chunkBase)
{
chunkBase = 36;
}
for (var i = bitArray.length; i > 0; i -= chunkSize)
{
var index = i - chunkSize;
if (index < 0)
{
index = 0;
}
var slice = bitArray.slice(index, i);
var chunk = parseInt(slice.join(""), 2).toString(chunkBase);
chunkArray.unshift(chunk);
}
return chunkArray.join(delim);
}
/*
* @param input : String
* @param length : Number > 1
* Target length of input after left-padded with zeros
* @return string
*/
function leadingZero (input, length)
{
input = String(input);
var inputLength = input.length;
if (inputLength >= length)
{
return input;
}
var padding = [];
padding.length = length + 1 - inputLength;
return padding.join("0") + input;
}
/*
* @param s : String
* @param chunkSize : optional Number = 53
* @param chunkBase : optional Number = 36
* @param delim : optional String = ","
* @return Array[string]
*/
function bitDecode (s, chunkSize, chunkBase, delim)
{
var chunkArray = s.split(delim || ",");
var bitArray = [];
if (!chunkSize || chunkSize > 53)
{
chunkSize = 53;
}
if (!chunkBase)
{
chunkBase = 36;
}
for (var i = 0, len = chunkArray.length; i < len; ++i)
{
bitArray = bitArray.concat(
leadingZero(
parseInt(chunkArray[i], chunkBase).toString(2),
chunkSize)
.split(""));
}
return bitArray;
}
var a = [];
for (var i = 250; i--;)
{
a[i] = +(Math.random() < 0.5);
}
/*
"11111110110011110011000011001010101010\
11010011111010010010100110100100010011001011001010111\
00100100010000101110011010000011100010010101011100011\
11100010110110111001101110000100011101101111101111100\
10001110110100010101110010011100110110100101110010011"
*/
a.join("")
/* "3hou1lt6,21ewvahkfvb,ck8t6olnmr,26lbvliu2rg,1dh74lghy8j" (55 characters) */
var s = bitEncode(a)
var a = bitDecode(s);
var originalLength = …;
a = a.slice(a.length - originalLength);
a = a.slice(-originalLength);
我刚刚编写了这个非常幼稚的实现。
它可以在 "111000111"
和 [['1',3],['0',3], ['1',3]]
之间进行转换(反之亦然)。
希望它能够很好地处理大型二进制字符串,这些字符串应该有很多重复的字符。在最坏的情况下(01010101...
),您将使用 1+7*n
个字符(其中 n
是输入字符串的大小)。
希望有人能提供更高效的解决方案?
var compress = function (input){
var output = [], current = null;
for (var t = 0; t < input.length; ++t ) {
if (current === null || current[0] !== input[t]) {
current = [input[t], 0];
output.push(current);
}
++ current[1];
}
return output;
};
var decompress = function (input) {
var output = '';
for (var t = 0; t < input.length; ++t) {
for (var u = 0; u < input[t][1]; ++u) {
output += input[t][0];
}
}
return output;
};
function binArray2HexArray (binArray) {
var hexArray = [];
while (binArray.length) {
hexArray.push(parseInt(binArray.splice(0,4),2).toString(16));
}
return hexArray;
}
显然,您可以将返回的数组连接起来,以将其转换为十六进制字符串。
如果您将数据填充到8位对齐,则可以通过将splice参数更改为以下内容,在每个循环中操作8位来加快函数速度:
binArray.splice(0,8)
这两个函数都需要一个字符串输入:
// input size must be less then 256 characters
// first byte in returned output is length of original string
// this is used during decoding for correct padding of last 8 bits
function encodeBits(input) {
var output = String.fromCharCode(input.length);
while(1) {
output += String.fromCharCode(parseInt(input.substr(0,8),2));
input = input.substr(8);
if(input.length == 0) {
break;
}
}
return output;
}
function decodeBits(input) {
var output = "";
var bits;
var finalLength = input.charCodeAt(0);
input = input.substr(1);
while(1) {
bits = input.charCodeAt(0).toString(2);
// string must be left padded with 0's
while(bits.length < 8) {
if((bits.length+output.length) == finalLength) {
break;
}
bits = "0"+bits;
}
output += bits;
input = input.substr(1);
if(input.length == 0) {
break;
}
}
return output;
}
编码
var instr = "101001110010100110010000111011111010110110001001111010110110";
var encStr = encodeBits(instr);
你可以使用escape对你的输出进行编码
var escapedStr = escape(encStr); // returns '%3C%A7%29%90%EF%AD%89%EB%06'
解码
使用 unescape 进行解码
var unescapedStr = unescape("%3C%A7%29%90%EF%AD%89%EB%06");
var bitStr = decodeBits(unescaped);
// bitStr now contains original input
"101001110010100110010000111011111010110110001001111010110110"
escape()
和unescape()
并不总是Unicode安全的。请使用encodeURIComponent()
和decodeURIComponent()
代替。btoa()
和atob()
是非标准的,即使根据参考文档,也不适用于Unicode字符。 - PointedEars为什么不使用base64?我之前写过类似的东西,但它使用了类型化数组:
https://github.com/beatgammit/base64-js/blob/master/lib/b64.js
基本上只需要将你的1和0转换成字节并进行base64编码即可。Base64可以在URL中传递,因此它适用于你的情况。
a.join("")
。 - PointedEarsString.prototype.substr()
是专有的。请使用String.prototype.substring()
。更好的选择是Array.prototype.slice()
。 - PointedEars