`

js版压缩解压算法

 
阅读更多

如题。附件是zip的

用法:

 

<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
		<title>zip解压</title>
	</head>

	<body>
		<div id="msg"> </div>
		先引入附件中的两个js:
		<script src="js/zipDeflate/inflate.js"></script>
		<script src="js/zipDeflate/deflate.js"></script>
		<script>
		function showResult(str){
			var msg=document.getElementById('msg')
			msg.innerText+=str+'\n'
			console.log(str)
		}
			//showResult(zip_inflate("123456789abc埃保常1`BAAOA1`BAAdA`eAAPA\n1`BAA[A1`BAA7B`]AArC"))
			//要压缩的字符串,中文要用 escape等方式编码
			var strstz1=escape("中文 123456789abc~!@#$%^&*()_+`-={}|[]\\;':\"<>?,./"); //123456789abc~!@#$%^&*()_+`-={}|[]\\;':\"<>?,./
			showResult("escape(\"中文\"): "+escape("中文"))
			showResult("strstz1: "+strstz1) 
			showResult("unescape(strstz1): "+unescape(strstz1))
			showResult("unescape(escape('中文')): "+unescape(escape('中文'))) //如果头部没有设置编码,那这个值 会乱码
			// showResult(str)
			var yasuo=zip_deflate(strstz1)
			showResult(yasuo)
			var jieya=zip_inflate(yasuo)
			//解压出来并解码:
			showResult("unescape(jieya): "+unescape(jieya))
			
			showResult("jieya==strstz1: "+(jieya==strstz1))
		</script>
		
	</body>
</html>

 

 

 

附: LZ77 算法的JS实现

<html>
<head>
<meta charset="utf-8" />
<title>LZ77</title>
<style>
* { font-size:12px; }
body { overflow:auto; background-color:buttonface; }
textarea { width:100%; height:240px; overflow:auto; }
#btn1 { width:100px; }
</style>
<script>
window.onload = init;

function $(s){ return document.getElementById(s); }

function init()
{
	$("txtS").focus();
	$("btn1").onclick = run;
	$("txtS").onkeydown = function ()
	{
		if (event.keyCode == 13 && event.ctrlKey)
		{
			run();
		}
	}
}

function run()
{
	var str = $("txtS").value;
	$("txtS").value = "";
	var lzc = new Lz77CompressDefer(str);
	var t = new Date();
	lzc.start(function (result)
	{
		$("txtR").value = Lz77SelfExtract(result);
		var tc = new Date() - t;
		$("txtS").value = eval($("txtR").value.substring(4));
		var td = new Date() - t - tc;
		alert("压缩完毕\r\n压缩比:"+($("txtR").value.length/str.length*100).toFixed(2)+"%\r\n压缩用时:"+tc+"ms\r\n解压用时:"+td+"ms\r\n校验:"+(str==$("txtS").value?"OK":"failed"));
	});
	
	function showProgress(){
		var p = lzc.status();
		if (p < 1)
		{
			$("txtS").value = "压缩中 ... " + (p*100).toFixed(2) + "%";
			setTimeout(showProgress, 300);
		}
	}
	
	showProgress();
	
	/*
	$("txtR").value = Lz77Compress(str);
	var tc = new Date() - t;
	$("txtS").value = Lz77Decompress($("txtR").value);
	var td = new Date() - t - tc;
	alert($("txtR").value.length/$("txtS").value.length+":"+tc+":"+td+":"+(str==$("txtS").value));
	*/
}


/*
 * 以 LZ77 原理实现的JS文本压缩算法
 * Author: Hutia
 *
 */

/*
LZ77基本原理:

1、从当前压缩位置开始,考察未编码的数据,并试图在滑动窗口中找出最长的匹配字符串,如果找到,则进行步骤 2,否则进行步骤 3。
2、输出三元符号组 ( off, len, c )。其中 off 为窗口中匹配字符串相对窗口边界的偏移,len 为可匹配的长度,c 为下一个字符。然后将窗口向后滑动 len + 1 个字符,继续步骤 1。
3、输出三元符号组 ( 0, 0, c )。其中 c 为下一个字符。然后将窗口向后滑动 len + 1 个字符,继续步骤 1。

变种:
1. 将匹配串和不能匹配的单个字符分别编码、分别输出,输出匹配串时不同时输出后续字符。

本算法变种:
1. 采用出现概率很低的前导字符P来区分匹配串输出和非匹配串。对于匹配串,输出 ( P, off, len ),对于非匹配串,输出 c。
   非匹配串中出现字符P时,输出PP来代替,以示和匹配串的区别。
   因此匹配串的输出 ( off, len ) 结果中,不可以出现字符P,以免产生混淆。
   本例中,取 (`) 作为前导字符。
   
2. 对于匹配串,输出为:
   前导字符 (`) + 偏移量 (3位,92进制 = 778688) + 匹配长度 (2位,92进制 = 8464)
   因此滑动窗大小为778688,最小的匹配长度为 7。
   
3. 本算法针对JS文件,为简化算法暂不考虑窗口滑动情况(JS文件通常不会大于700K)。对于文件大于778688字节的情况使用本算法会出错。将来可以实现滑动窗口或分段压缩。
4. 本例中为简化算法,将 off 与 len 转换为 92 进制的字符串,并且将低位放在左侧,高位放在右侧。

作者:Hutia
Email: Hutia2@163.com
转载请注明出处

*/

var NC = [], CN = [];
NC = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&*()-=[]\;',./_+{}|:\"<>?".split("");
for (var i=0; i<NC.length; i++) CN[NC[i]] = i;



function Lz77Compress(input)
{
	/*LZ77压缩算法 - Hutia - JS版*/
	
	/*变量声明*/
	var p = 0; //扫描指针
	var lp = 0; //链表查询指针
	var len = input.length; //输入字符串的长度
	var output = []; //输出
	var index = ""; //索引
	var head = []; //索引头信息
	var prev = []; //位置链表
	var match_off = 0; //匹配位置的偏移量
	var match_len = 0; //发生匹配的长度
	var last_match_off = 0; //上一次匹配位置的偏移量
	var last_match_len = 0; //上一次发生匹配的长度
	var j = 0; //循环变量
	
	/*循环扫描*/
	for (p=0; p<len; p++)
	{
		index = input.substring(p, p+7); //取当前字符开始的7个字符作为索引
		
		/*链表维护*/
		prev[p] = head[index]; //当前头位置进链表
		head[index] = p; //保存现在位置进头信息
		/*匹配*/
		lp = p; //初始化链表查询指针
		match_len = 0; //初始化匹配长度
		match_off = 0; //初始化匹配位置
		if (prev[lp]) //如果链表上存在上一个匹配
		{
			/*匹配查询*/
			while (prev[lp]) //依次查看链表上的每个位置
			{
				lp = prev[lp]; //取出链表上的前一个位置到链表查询指针
				for (j=1; j<8464 && lp+j<p; j++) //寻找此位置的最长匹配,匹配长度不能超过8464 (92进制的2个字节长度),也不能超过当前指针位置
				{
					if (input.substring(lp, lp + j) != input.substring(p, p + j)) break;
				}
				j--; //计算最长匹配
				if (j > 7 && j > match_len) //如果此匹配比已发现的匹配长
				{
					match_len = j; //记录匹配长度
					match_off = lp; //记录匹配位置
				}
			}
			
			/*匹配处理*/
			if (match_len > 7) //如果找到了符合要求的匹配
			{
				if (last_match_len != 0 && last_match_len < match_len) //如果上次匹配存在,且长度没有这次匹配的长度大
				{
					/*懒惰模式*/
					output_unmatch(input.charAt(p - 1)); //放弃上次匹配,将字符直接输出
					last_match_off = match_off; //记录此次的匹配位置
					last_match_len = match_len; //记录此次的匹配长度
				}
				else if (last_match_len != 0) //如果上次匹配存在,且长度比这次匹配的长度大
				{
					/*处理上次的懒惰模式*/
					output_match(); //输出上次的匹配
				}
				else //如果上次匹配不存在
				{
					/*懒惰模式*/
					last_match_off = match_off; //记录此次的匹配位置
					last_match_len = match_len; //记录此次的匹配长度
				}
			}
			else //如果找不到符合要求的匹配(例如匹配超出当前指针)
			{
				if (last_match_len != 0) //如果上次匹配存在
				{
					/*处理上次的懒惰模式*/
					output_match(); //输出上次的匹配
					
				}
				else
				{
					output_unmatch(input.charAt(p)); //直接输出当前的字符
				}
			}
		}
		else //如果当前不存在匹配
		{
			if (last_match_len != 0) //如果之前发生了匹配
			{
				/*处理上次的懒惰模式*/
				output_match(); //输出匹配
			}
			else
			{
				output_unmatch(input.charAt(p)); //直接输出当前的字符
			}
		}
	} //循环扫描结束
	
	/*边界处理*/
	if (last_match_len != 0) //如果之前发生了匹配
	{
		/*处理上次的懒惰模式*/
		output_match(); //输出匹配
	}
	
	/*输出*/
	return output.join("");
	
	function output_match()
	{
		output.push("`"); //输出前缀符
		output.push(N2C(last_match_off, 3)); //输出3字节偏移量
		output.push(N2C(last_match_len, 2)); //输出2字节匹配长度
		p += last_match_len - 2; //移动当前指针到匹配串的末尾(因为懒惰模式,此时 p 指向 last_match_off + 1 的位置,所以应 -2 )
		last_match_off = 0; //清空匹配位置
		last_match_len = 0; //清空匹配长度
	}
	
	function output_unmatch(c)
	{
		output.push(c == "`" ? "``" : c); //输出未匹配的字符
	}
}

function Lz77Decompress(input)
{
	/*LZ77解压缩算法 - Hutia - JS版*/
	
	/*变量声明*/
	var p = 0; //扫描指针
	var len = input.length; //输入字符串的长度
	var output = []; //输出
	var match_off = 0; //匹配位置的偏移量
	var match_len = 0; //发生匹配的长度
	
	/*循环扫描*/
	for (p=0; p<len; p++)
	{
		if (input.charAt(p) == "`") //如果发现前缀标记
		{
			if (input.charAt(p + 1) == "`") //如果是转义前缀
			{
				output.push("`"); //直接输出字符 "`"
				p++; //指针后移,跳过下一个字符
			}
			else //如果是压缩编码
			{
				match_off = C2N(input.substring(p+1, p+4)); //取出其 1-3 个字符,算出偏移量
				match_len = C2N(input.substring(p+4, p+6)); //取出其 4-5 字符,算出匹配长度
				output = [].concat(output.join("")); //整理输出内容
				output.push(output[0].substring(match_off, match_off + match_len)); //自输出内容的相应偏移量位置取出编码所代表的字符串
				p += 5; //指针后移,跳过下5个字符
			}
		}
		else //如果没有发现前缀标记
		{
			output.push(input.charAt(p)); //直接输出相应的字符
		}
	}
	
	/*输出*/
	return output.join("");
}

/*LZ77解压缩算法 - Hutia - JS / mini 版*/
hutia = function(s){var A="charAt",p=-1,l=s.length,o=[],m,a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&*()-=[]\;',./_+{}|:\"<>?".split(""),_=[];while(++p<92)_[a[p]]=p;function $(c){var l=c.length,r=0,i=-1;while(++i<l)r+=_[c[A](i)]*Math.pow(92,i);return r;}p=-1;while(++p<l){if(s[A](p)=="`"){if(s[A](p+1)=="`")p++,o.push("`");else{m=$(s.substring(p+1,p+4));o=[].concat(o.join(""));o.push(o[0].substring(m,m+$(s.substring(p+4,p+6))));p+=5;}}else o.push(s.charAt(p));}return o.join("");}

function Lz77SelfExtract(s)
{
	return "eval(("+String(hutia)+")(\""+s.replace(/\\/g,"\\\\").replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\"/g,"\\\"")+"\"));";
}

function Lz77CompressDefer(input)
{
	/*LZ77压缩算法 - Hutia - JS / Defer 版*/
	
	/*变量声明*/
	var p = 0; //扫描指针
	var lp = 0; //链表查询指针
	var len = input.length; //输入字符串的长度
	var output = []; //输出
	var index = ""; //索引
	var head = []; //索引头信息
	var prev = []; //位置链表
	var match_off = 0; //匹配位置的偏移量
	var match_len = 0; //发生匹配的长度
	var last_match_off = 0; //上一次匹配位置的偏移量
	var last_match_len = 0; //上一次发生匹配的长度
	var j = 0; //循环变量
	var callback; //回调函数
	
	this.start = function(fn)
	{
		this.start = function(){}
		callback = fn;
		run();
	}
	
	this.status = function ()
	{
		return p / len;
	}
	
	function run()
	{
		var inner_i = 0;
		/*循环扫描*/
		for (; p<len; p++)
		{
			if (++inner_i > 400)
			{
				return setTimeout(run);
			}
			
			index = input.substring(p, p+7); //取当前字符开始的7个字符作为索引
			
			/*链表维护*/
			prev[p] = head[index]; //当前头位置进链表
			head[index] = p; //保存现在位置进头信息
			/*匹配*/
			lp = p; //初始化链表查询指针
			match_len = 0; //初始化匹配长度
			match_off = 0; //初始化匹配位置
			
			if (prev[lp]) //如果链表上存在上一个匹配
			{
				/*匹配查询*/
				while (prev[lp]) //依次查看链表上的每个位置
				{
					lp = prev[lp]; //取出链表上的前一个位置到链表查询指针
					for (j=1; j<8464 && lp+j<p; j++) //寻找此位置的最长匹配,匹配长度不能超过8464 (92进制的2个字节长度),也不能超过当前指针位置
					{
						if (input.substring(lp, lp + j) != input.substring(p, p + j)) break;
					}
					j--; //计算最长匹配
					if (j > 7 && j > match_len) //如果此匹配比已发现的匹配长
					{
						match_len = j; //记录匹配长度
						match_off = lp; //记录匹配位置
					}
				}
				
				/*匹配处理*/
				if (match_len > 7) //如果找到了符合要求的匹配
				{
					if (last_match_len != 0 && last_match_len < match_len) //如果上次匹配存在,且长度没有这次匹配的长度大
					{
						/*懒惰模式*/
						output_unmatch(input.charAt(p - 1)); //放弃上次匹配,将字符直接输出
						last_match_off = match_off; //记录此次的匹配位置
						last_match_len = match_len; //记录此次的匹配长度
					}
					else if (last_match_len != 0) //如果上次匹配存在,且长度比这次匹配的长度大
					{
						/*处理上次的懒惰模式*/
						output_match(); //输出上次的匹配
					}
					else //如果上次匹配不存在
					{
						/*懒惰模式*/
						last_match_off = match_off; //记录此次的匹配位置
						last_match_len = match_len; //记录此次的匹配长度
					}
				}
				else //如果找不到符合要求的匹配(例如匹配超出当前指针)
				{
					if (last_match_len != 0) //如果上次匹配存在
					{
						/*处理上次的懒惰模式*/
						output_match(); //输出上次的匹配
						
					}
					else
					{
						output_unmatch(input.charAt(p)); //直接输出当前的字符
					}
				}
			}
			else //如果当前不存在匹配
			{
				if (last_match_len != 0) //如果之前发生了匹配
				{
					/*处理上次的懒惰模式*/
					output_match(); //输出匹配
				}
				else
				{
					output_unmatch(input.charAt(p)); //直接输出当前的字符
				}
			}
		} //循环扫描结束
		
		/*边界处理*/
		if (last_match_len != 0) //如果之前发生了匹配
		{
			/*处理上次的懒惰模式*/
			output_match(); //输出匹配
		}
		
		/*回调输出*/
		callback(output.join(""));
	} //end of run
	
	function output_match()
	{
		output.push("`"); //输出前缀符
		output.push(N2C(last_match_off, 3)); //输出3字节偏移量
		output.push(N2C(last_match_len, 2)); //输出2字节匹配长度
		p += last_match_len - 2; //移动当前指针到匹配串的末尾(因为懒惰模式,此时 p 指向 last_match_off + 1 的位置,所以应 -2 )
		last_match_off = 0; //清空匹配位置
		last_match_len = 0; //清空匹配长度
	}
	
	function output_unmatch(c)
	{
		output.push(c == "`" ? "``" : c); //输出未匹配的字符
	}
}


function C2N(c) //将 92 进制字符串(高位在右)转换为 10 进制数字
{
	var len = c.length;
	var re = 0;
	for (var i=0; i<len; i++)
	{
		re += CN[c.charAt(i)] * Math.pow(92, i);
	}
	return re;
}

function N2C(n, len) //将 10 进制数字转换为指定长度的 92 进制字符串,高位在右
{
	var re = [];
	for (var i=0; i<len; i++)
	{
		re[i] = NC[n % 92];
		n = n / 92 | 0;
	}
	return re.join("");
}

</script>
</head>

<body>
<textarea id="txtS"></textarea>
<textarea id="txtR"></textarea>
<br/>
<input type="button" value="Go" id="btn1">
</body>
</html>

 

x@��`t$

J������؇x6��0P�����iCn

 

%MӬGk%;
|
��zi_N5��2��)­

分享到:
评论

相关推荐

    VB-21种加密解密算法和54种压缩解压算法的源码

    本资源"VB-21种加密解密算法和54种压缩解压算法的源码"提供了一个宝贵的资料库,帮助开发者深入理解和实践这些技术。 首先,让我们探讨21种加密解密算法: 1. **对称加密**:如DES(Data Encryption Standard),...

    lzss压缩/解压算法

    在实现LZSS压缩/解压算法时,有几个关键点需要注意: - **跨平台性**:为了确保代码能在不同平台上运行,需要使用标准C或C++语言,并且避免使用特定平台的库函数或硬件特性。同时,需要考虑字节序问题,尤其是当...

    三个简单实用的压缩解压算法实现

    解压缩时,根据这个信息在已解压的数据中查找并复制匹配串。LZSS适用于实时数据流压缩,且更易于实现。 最后,SCZ算法,即简单的压缩算法,可能是一种较简单的压缩方法,通常用于教学或实验目的。其原理可能是基于...

    C++做的Huffman压缩解压算法

    综上所述,C++实现的Huffman压缩解压算法涉及了数据结构、算法和文件处理等多个方面的知识。通过这个项目,我们可以学习到如何运用C++实现复杂的数据处理任务,并加深对数据压缩原理的理解。在实际应用中,Huffman...

    实现lzss压缩/解压算法

    以下是关于LZSS压缩/解压算法的详细说明: ### LZSS算法概述 LZSS算法基于滑动窗口和匹配查找的概念。它将输入数据分成固定长度的块,并在当前窗口内寻找最长的前缀匹配。找到的匹配将被编码为一个“查找长度”和一...

    LZ78算法实现对任意字符串的压缩与解压

    LZ78压缩算法是一种基于字典的无损数据压缩方法,由Abraham Lempel、Jacob Ziv和Stu Arkin在1977年提出。它通过查找输入字符串中的最长匹配前缀来构建一个新的编码,从而实现数据的压缩。这种算法的主要思想是创建一...

    lzw压缩解压算法源码

    LZW(Lempel-Ziv-Welch)压缩算法是一种数据压缩方法,广泛应用于文本、图像和其他类型的数据。它的核心思想是通过构建一个字典来查找重复的模式,并用更短的编码来表示这些模式,从而实现数据压缩。在本文中,我们...

    vb21种加密解密算法和54种压缩解压算法的源码

    标题提到的“vb21种加密解密算法和54种压缩解压算法的源码”提供了一个丰富的资源库,涵盖了多种常见的加密和压缩方法。 一、加密解密算法 1. 对称加密:这类算法使用相同的密钥进行加密和解密,如DES(Data ...

    21种加密_解密算法和54种压缩_解压算法的VB源码

    在VB(Visual Basic)编程环境中,开发者经常需要处理数据的安全性和存储效率问题,这就涉及到加密解密和压缩解压算法的应用。"21种加密_解密算法和54种压缩_解压算法的VB源码"是一个宝贵的资源库,为开发者提供了...

    LZW压缩 解压算法

    用c语言实现的lzw算法 压缩 和解压缩

    RLE算法压缩解压源代码文件

    RLE(Run-Length Encoding)是一种简单的无损数据压缩算法,主要应用于处理连续重复的数据。它通过将连续出现的相同字符或数值用一个字符加计数的方式进行编码,从而减少数据量,达到压缩的目的。在本压缩包文件中,...

    LZ77数据无损压缩解压算法,建好工程可以直接运行

    LZ77(Lempel-Ziv-Welch)数据压缩算法是一种无损的数据压缩方法,广泛应用于文本、图像和音频文件的压缩中。它的基本原理是通过查找输入数据中的重复模式并用短的编码来表示这些模式,从而达到减少数据量的目的。...

    lzw压缩解压算法VB实现

    LZW(Lempel-Ziv-Welch)压缩算法是一种数据压缩方法,广泛应用于文本、图像和其他类型的数据。在VB(Visual Basic)环境下实现LZW压缩和解压缩,可以帮助开发者理解算法原理,并将其应用于实际项目中。以下是关于...

    压缩_解压缩算法

    在计算机科学领域,压缩与解压缩算法是至关重要的技术,它们用于减少数据的存储空间,提高传输效率。这里我们主要探讨ACMS、ASH、COM、HA、CAB和LZSS这六种压缩算法,以及可能涉及的压缩工具。 1. ACMS(Adaptive ...

    哈夫曼压缩解压算法-C语言

    哈夫曼编码(Huffman Coding)是一种数据压缩算法,由美国计算机科学家大卫·艾尔曼在1952年提出。它的主要原理是基于字符出现频率构建最优的二叉树,进而为每个字符生成最短的唯一编码,使得常用字符在编码过程中...

    RLE压缩算法C语言实现

    RLE(Run-Length Encoding,行程长度编码)是一种简单的无损数据压缩算法,它通过寻找连续重复的字符或字节,并用一对数值表示该字符或字节的重复次数和该字符本身,来达到压缩数据的目的。在C语言中实现RLE算法,...

    LZ77数据无算压缩解压算法

    LZ77(Lempel-Ziv-77)数据无损压缩算法是计算机科学领域中一种广泛应用的无损压缩方法,由Jacob Ziv和Abraham Lempel于1977年提出。该算法主要基于滑动窗口的概念,通过查找输入数据中的重复模式来实现压缩,这些...

    大量加密解密及压缩解压算法VB源码包

    这个名为“大量加密解密及压缩解压算法VB源码包”的资源提供了丰富的VB编程实现,涵盖了21种不同的加密算法和54种压缩解压算法。以下是这些算法的一些详细说明: **加密算法**: 1. **AES(高级加密标准)**:一种...

    哈夫曼压缩与解压算法(可以直接运行)

    哈夫曼编码是一种高效的数据压缩算法,由大卫·哈夫曼在1952年提出,主要用于无损数据压缩。这种编码方式利用字符出现频率构建最优的二叉树(哈夫曼树),使得频繁出现的字符拥有较短的编码,不常出现的字符则有较长...

    几种能用于小ram单片机的压缩算法.7z

    针对这类情况,开发者经常需要寻找适合小RAM单片机的压缩算法来优化存储和传输效率。本压缩包文件包含了多种这样的算法,它们在VSCode环境下已经验证通过,除了gzip由于其较高内存需求未在单片机上实际运行外,其他...

Global site tag (gtag.js) - Google Analytics