论坛首页 Web前端技术论坛

1kjs,独创压缩算法,纯Js实现GBK编码,超小体积挑战纯忽悠版本VBS版

浏览 5556 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2011-09-20   最后修改:2011-09-20

废话不多说!

 

先上地址和演示

 

这次发的组件是因为上次遇到一个编码问题而创作的!

 

众所周知,Js这个东西是老外开发的,所有,他没有内置GBK编码的功能,而在中国,大家都操作系统(windows)默认的codepage就是GBK的,所有呢,当中文出现在URL里面发送的时候,浏览器就会进行一次URLEncode!

 

而我们平时想将中文在Js中进行GBK编码,那几乎是不可能的!网上的实现,大多数我只能说是纯忽悠吧!鄙视那些漫天转载而不经思考的人!

 

现在,就有我这个组件来实现纯Js进行GBK编码和解码吧!

 

当你收到%DA%4D这种GBK编码形式,你可以调用我的decode来实现解码哦!

同样,传入中文 encode('测试中文')将输出 %B2%E2%CA%D4%D6%D0%CE%C4

 

针对组件的实现,还是很简单的,而简单不代表没有问题,这里的问题比上次提到的省市三级联动组件更加严峻!

 

因为数据量实在太大了,不过这次的压缩算法的实现确实是解决整个问题的关键!

至于本组件采用了什么压缩算法,先让大家思考下,后期将放出全部完整的原理解析!(组件的源码请查看

 

 

chrome下文件上传不了,郁闷,下载源码请移步组件的源码

   发表时间:2011-09-20  
LZ果然很闲...

其实你还可以进一步压缩,那一长串数据大部分都是0~f,可以用base64进行编码,1字符表达的数据量分别是4bit和6bit,能压缩33%左右。

P.S.
为什么还要用GBK呢?utf-8就很方便,JS还有内置编码方法:encodeURIComponent/decodeURIComponent。
当然如果是在老系统的基础上做二次开发,那就没办法了。

再P.S.
其实上次你发的那个省市县联动的JS,我也蛋疼了 ,用huffman+base64试着压缩了一下,huffman树占7K左右,base64数据23K,算上代码可能比你的压缩率高点,不过只是尝试下,huffman反序列化没有写。
附上代码,蛋疼的时候可以研究研究:
(你的原数据截掉了,太长了,代码写得很随意,将就下吧)
(function(){
	var str = "北京市:北京市#东城区|西城区|崇文区|宣武区|朝阳区|丰台区|石景山区|海淀区|门头沟区|房山区|通州区*"
	String.prototype.getACLength = function(){
		return encodeURIComponent(this).replace(/%\w\w/g, 'a').length;
	};
	var originalLength = str.getACLength();
	// 原始数据字节数
	console.log("原始数据大小:" + originalLength);

	// 计算字频率
	var i, map = {}, c;
	for(i=0; i<str.length; i++){
		c = str[i];
		map[c] = (map[c] || 0) + 1;
	}
	
	var arr = [];
	for(c in map){
		if(map.hasOwnProperty(c)){
			arr.push({
				num : map[c],
				c : c
			});
		}
	}
	
	// 按频率生成huffman树
	var Node = function(a, b){
		this.left = a;
		this.right = b;
		this.num = a.num + b.num;
	};
	
	var left, right;
	while(arr.length>1){
		arr.sort(function(a, b){
			return a.num-b.num;
		});
		left = arr[0];
		right = arr[1];
		arr.splice(0, 2, new Node(left, right));
	}
	var huffmanTree = arr[0];
	
	// 将huffman树序列化输出(compressTree) + 生成反查字典(字 -> huffman编码)
	var results = [], compressTree = [];
	function output(node, base){
		base = base || "";
		if(node instanceof Node){
			compressTree.push(":");
			output(node.left, base + "0");
			compressTree.push(",");
			output(node.right, base + "1");
		}else{
			compressTree.push(node.c.charCodeAt(0).toString(36));
			results.push({
				code : base,
				c : node.c
			});
		}
	}
	output(huffmanTree);
	compressTree = compressTree.join("");
	
	results.sort(function(a, b){
		var len = a.code.length - b.code.length;
		if(len === 0){
			return a.code - b.code;
		}
		return len;
	});
	
	// 反查字典
	var strs = [], result, dictMap = {};
	for(i=0; i<results.length; i++){
		result = results[i];
		strs.push(result.code + " : " + result.c);
		dictMap[result.c] = result.code;
	}
	var huffmanTreeLength = compressTree.getACLength();
	console.log("huffman树数据大小:" + huffmanTreeLength);
	
	//console.log(compressTree);
	//console.log(strs.join("\n"));
	
	// huffman编码处理
	function encode(str, dictMap){
		return str.replace(/./g, function(c){
			return dictMap[c];
		});
	}
	
	// 生成base64字典
	var base64Map = {}, reverseBase64Map = {}, key, value, base64List = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	for(i=0; i<64; i++){
		key = i.toString(2);
		if(key.length<6){
			key = "000000".slice(key.length) + key;
		}
		base64Map[key] = base64List[i];
		reverseBase64Map[base64List[i]] = key;
	}
	// base64编码处理
	function toBase64(str){
		if(str.length%24 !== 0){ // 补全24位整数
			str = str + "000000000000000000000000".slice(str.length%24);
		}
		return str.replace(/[01]{6}/g, function(key){
			return base64Map[key];
		});
	}
	// base64解码处理
	function fromBase64(str){
		return str.replace(/./g, function(c){
			return reverseBase64Map[c];
		});
	}
	
	var encodedStr = encode(str, dictMap);
	var huffmanLength = encodedStr.getACLength();
	var base64Str = toBase64(encodedStr);
	var base64Length = base64Str.getACLength();
	console.log("huffman+base64编码最终大小:" + base64Length);
	console.log("压缩率:" + ( (huffmanTreeLength + base64Length) / originalLength * 100 ).toFixed(2) + "%" );
	//console.log(base64Str, base64Str.length);
	// huffman解码处理
	function decode(str, huffmanTree){
		var node = huffmanTree, plain = [], c, pos = 0, b;
		while(pos < str.length){
			b = str.charAt(pos);
			if(b==="0"){
				node = node.left;
			}else{
				node = node.right;
			}
			if(node.c){
				plain.push(node.c);
				node = huffmanTree;
			}
			pos++;
		}
		plain = plain.join("");
		var lastAvalibleIndex = plain.lastIndexOf("*");
		return plain.slice(0, lastAvalibleIndex+1);
	}
	
	console.log("验证解码:" + (decode(fromBase64(base64Str), huffmanTree) === str ? "成功" : "失败") );
	//console.log(decode(fromBase64(base64Str), huffmanTree))
})();


实际数据输出结果
引用

原始数据大小:51862
huffman树数据大小:7001
huffman+base64编码最终大小:23344
压缩率:58.51%
验证解码:成功
0 请登录后投票
   发表时间:2012-05-29   最后修改:2012-05-29
楼主绝对是闲得蛋疼!!!
我写一个支持GBK的URLEncode和URLDecode只要不到1K的代码你信不???


给你看个示例代码吧!
var iframe=document.createElement("iframe");
iframe.src="about:blank";
iframe.setAttribute("style","display:none;visibility:hidden;");
document.body.appendChild(iframe);
var d=iframe.contentWindow.document;
d.charset=d.characterSet="GBK";
function getGBKEscape(s) {
    d.write("<body><a href='?"+s+"'>X</a></body>");
    d.close();
    var url=d.body.firstChild.href;
    return url.substr(url.lastIndexOf("?")+1);
}


看明白木有啊?哪需要什么把所有GBK字全写到JS中哪

http://www.jamcode.org/
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics