lz77 压缩算法 JS实现, 参考了网上的一个例子, 重写过的, 压缩效果一般 function lz77_c(str) { // 将字符串转换为 UTF-8 字节数组 function str_to_utf8(str) { var r = []; for(var i=0;i<str.length;i++) { var ch = str.charCodeAt(i); if(ch <= 0x7f) r[r.length] = ch; else if(ch<= 0x7ff) { r[r.length] = 0xC0 | (ch>>6); r[r.length] = 0x80 | (ch & 0x3F); } else if(ch<= 0xFFFF) { r[r.length] = 0xE0 | (ch>>12); r[r.length] = 0x80 | ((ch>>6) & 0x3F); r[r.length] = 0x80 | (ch & 0x3F); } } return r; } str = str_to_utf8(str); var X = 1<<15 /* 距离用15位二进制表示*/, L = 32 /* 匹配长度用5位二进制*/; // 在字符串 str 中 比较a,b位置处的最长匹配 function strcmp(str, a, b) { var i = 0, sl = str.length; for(;i< L && a+i<sl && b+i<sl;i++) if(str[a+i] != str[b+i]) return i; return i<L?i:L; } // 三字节字符串位置索引 {"abc":[3,7,19],"def":[2,23]} var dic = {}; // 存放结果的数组 每单元存放 24个二进制位 (3个字节) // 第一单元用于表示最后一个单元剩余未用的二进制位数量 var r = [0]; // 向数组r中写入值为v的n位二进制数 function write_bits(r, v, n) { if(n<=0) return; if(r[0] == 0) { r[r.length] = 0; r[0] = 24; } if(n < r[0]) { r[0] -= n r[r.length-1] |= v<<r[0]; }else{ var n1 = n - r[0]; r[r.length-1] |= v>>n1; r[0] = 0; write_bits(r, v & (0xffffff >> (24-n1)), n1); } } // 扫描字符串开始编码 for(var i=0;i<str.length;i++) { var max_len=0, max_off=0;// 最长匹配和位置 if( i< str.length-3) { var d1 = String.fromCharCode(str[i],str[i+1],str[i+2]); //三字节字符串加入索引 if(dic[d1]) { dic[d1].push(i); }else{ dic[d1] = [i]; } for(var k=dic[d1].length-2; k>=0; k--) { var j = dic[d1][k]; if(j <= i - X) { break; } var len = strcmp(str, i, j); //在索引位置处查找最长匹配 if(len > max_len) { max_len = len; max_off = i - j; } } } if(max_off < X && max_len > 3) { // 找到最长匹配 write_bits(r, 1,1); // 写入标识 write_bits(r, max_off, 15); // 写入位置 write_bits(r, max_len-3, 5); // 写入长度 i+= max_len-1; }else{ write_bits(r, 0,1); // 没找到 写入标识和原字符 write_bits(r, str[i], 8); } } // BASE64 编码 var z = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".split(""); var rs = []; for(var i=0;i<r.length;i++) { rs[rs.length] = z[(r[i]>>18) & 0x3f]; rs[rs.length] = z[(r[i]>>12) & 0x3f]; rs[rs.length] = z[(r[i]>> 6) & 0x3f]; rs[rs.length] = z[(r[i] ) & 0x3f]; } return rs.join(""); } function lz77_d(s) { var i,j, ch, z ={}, w = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''); for(i=0;i<64;i++) // base64解码 z[w[i]] = i; var r = [], x=1, y=0; // 将BASE64转为整型数组 for(i=0,j=0;i<s.length;i+=4,j++) r[j] = (z[s.charAt(i)]<<18) | (z[s.charAt(i+1)]<<12) | (z[s.charAt(i+2)]<<6) | (z[s.charAt(i+3)]); // 读取二进制位 r 数组 n 读取位数 从 x 单元的第 y 位开始读 function read_bits(r, n){ var v, ny; if(r.length*24 - r[0] - (x*24+y) < n) return -1; ny = 24-y; if(n <= ny) { v = (r[x]>>(ny-n)) & (0xffffff >> (24-n)); y += n; if(y==24) { x++;y=0; } return v; }else{ v = (r[x] & (0xffffff >> y)) << (n-ny); x++;y=0; v |= read_bits(r, n-ny); return v; } } s = []; //开始解码 结果放到 s 里 j=0; for(;;) { var c = read_bits(r, 1); // 读取一位标志位 if(c<0)break; if(c==0){ s[s.length] = read_bits(r, 8);//读取一个字节 j++; }else{ var off = read_bits(r, 15);// 位置 var len = read_bits(r, 5)+3; // 长度 for(var k=0;k<len;k++) { // copy s[s.length]= s[j-off]; j++; } } } // UTF8字节数组转为 string function utf8_to_str(s) { var r = [], fc = String.fromCharCode; for(var i=0;i<s.length;i++) { var ch = s[i]; if(ch< 0x80) r[r.length] = fc(s[i]); else if(ch < 0xE0) { r[r.length] = fc( ((s[i]&0x1f) << 6) | (s[i+1] & 0x3f)); i++; }else if(ch < 0xF0) { r[r.length] = fc( ((s[i] & 0xF) << 12) | ((s[i+1] & 0x3f)<<6) | (s[i+2] & 0x3f)); i+=2; } } return r.join(''); } s = utf8_to_str(s); return s; } function println(){ var m = ""; for(var i=0;i<arguments.length;i++) m += arguments[i] + " "; m = m.replace("<","<"); m = m.replace(">",">"); document.getElementById("msg").innerHTML += m + "<br>"; } function compress() { var str = document.getElementById("ta_in").value; var ccc = lz77_c(str); var dstr = lz77_d(ccc); var func_d = "(function(u){var l,h,b,o={},t='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split('');for(l=0;l<64;l++){o[t[l]]=l}var a=[],q=1,p=0;for(l=0,h=0;l<u.length;l+=4,h++){a[h]=(o[u.charAt(l)]<<18)|(o[u.charAt(l+1)]<<12)|(o[u.charAt(l+2)]<<6)|(o[u.charAt(l+3)])}function d(i,k){var c,j;if(i.length*24-i[0]-(q*24+p)<k){return -1}j=24-p;if(k<=j){c=(i[q]>>(j-k))&(16777215>>(24-k));p+=k;if(p==24){q++;p=0}return c}else{c=(i[q]&(16777215>>p))<<(k-j);q++;p=0;c|=d(i,k-j);return c}}u=[];h=0;for(;;){var n=d(a,1);if(n<0){break}if(n==0){u[u.length]=d(a,8);h++}else{var e=d(a,15);var m=d(a,5)+3;for(var f=0;f<m;f++){u[u.length]=u[h-e];h++}}}function g(v){var w=[],k=String.fromCharCode;for(var c=0;c<v.length;c++){var j=v[c];if(j<128){w[w.length]=k(v[c])}else{if(j<224){w[w.length]=k(((v[c]&31)<<6)|(v[c+1]&63));c++}else{if(j<240){w[w.length]=k(((v[c]&15)<<12)|((v[c+1]&63)<<6)|(v[c+2]&63));c+=2}}}}return w.join('')}u=g(u);return u})"; println(str.length); println(ccc.length); println(str == dstr,str.length,dstr.length); document.getElementById("ta_out").value = "eval("+func_d+"(/""+ccc+"/"));"; println(document.getElementById("ta_out").value.length); }