JS操作二進制很麻煩,而且一直沒有一個好的無損壓縮工具來實現純文本的壓縮。
所以鑽研了一段時間的gzip,後來發現還是僅用 LZ77 比較容易實現,gzip中的 haffman 壓縮部分對於JS來說太難搞了。
代碼如下,注釋的非常完整,所以就不多說了,有興趣的可以仔細研究下:
運行代碼框<html> <head> <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 進制的字符串,並且將低位放在左側,高位放在右側。