Javascript Compressor がほぼ完成しました。正規表現のエラーチェックと括弧の数を数えてエラーがある場合に表示されます。Compression Ratio も表示させるようにしました。
以前の記事を改良しました。
正規表現部分の[ ] 内の"/" とスペースがあった場合に圧縮時に(スペースがある場合のみ)スペースが消てしまうので今回は、ループさせてRegExp をecmascript 評価 (eval)してチェックするようにしました。
例: exp=/[ / ]/;
通常は、exp=/[ \/ ]/; と書くのですが、実際に正規表現の [ ] 内に"/" があってもjavascript ではエラーになりません。普通に書くと、/ ==> \/, space ==> \s となるのですが、文字コードなどが絡んでどうしても特殊な書き方が必要な例もあるかもしれないのでそれに対応しました。Javascript のコードはとても柔軟性が高いのでまだ100%とは言えないかもしれませんが、一般的なJavascriptのコードではエラーはないと思います。
また今回、Javascript Code Prettifier もセレクトメニューに追加しました。
こちらの記事に詳細があります。使い方はただ貼り付けるだけなので簡単です。(js ファイルなどのセットアップせずに何ヶ所でも貼り付けられます。)
見た目は下にあるJavascript compressor のソースコードのようになります。
Google Gadget の貼り付けコードです。ブログやウェブページに貼り付けられます。
Source code of modified Javascript Compressor function.
Modified on 1 Oct. 2008
1 /****************************************************************
2 2008 (C)samurai-logic.com
3
4 Javascript Compressor
5
6 Last Modified 1 Oct. 2008
7 ****************************************************************/
8 function $compress(str){
9
10 var Size=str.length;
11
12 //if(/\n/g.test(str)) return("no end of line");
13
14 str=str.replace(/\t+/g," ");
15
16 Reg=/([^\d\w]\n[^\d\w]|[^\d\w]\s[^\d\w]|[\d\w]\s[^\d\w\$\_\#]|[^\d\w]\s[\d\w])/;
17
18 //Exp=/[^\\]\/[^\/]*([\s\,\;]*)((\,\s*(\"|\')|(\w+)\s*\(\s*\/*)[\s\S]+|\/\/[\s\S]+|\/\*[\s\S]+|\s{2,}[\s\S]+|\s*)\n*/;
19 //Exp=/[^\\]\/([^\/])?(\s)*(([\,\s]*(\"|\')|(\w+)\s*\(\s*\/*)[\s\S]+|\/\/[\s\S]+|\/\*[\s\S]+|\s{2,}[\s\S]+|\s*)\n*/;
20
21 //Basic Exp
22 Exp=/[^\\]\/([^\/])/;
23
24 chr=/(\(|\=|\[|\:|\||\&|\!|\,)/; // new reg
25
26 //d_q=/([^\\]\"[^\"]*[^\:]|[^\"]\"[\s]*[\:\,\}\]\)\;\.])/;
27 //s_q=/([^\\]\'[^\']*[^\:]|[^\']\'[\s]*[\:\,\}\]\)\;\.])/;
28 //d_q=/([^\\]\"|[^\"]\")/;
29 //s_q=/([^\\]\'|[^\']\')/;
30
31 //modified 1 Oct. 2008 don't need to replace \\\" and \\\'...
32 d_q=/[^\\]\"/; //replace(/\\\\|\\\"/g,"xx") temp before search(d_q)
33 s_q=/[^\\]\'/; //replace(/\\\\|\\\'/g,"xx") temp before search(s_q)
34
35 bracket=new Array();
36
37 bracket[0]=0; bracket[1]=0; bracket[2]=0; bracket[3]="";
38
39 var CODE = "";
40 var cmt = false;
41 var arg = -1;
42 var pos = end = 0;
43 var last=" ";
44 var temp="";
45 var LEN=str.length;
46 var retrn = false; // for regexp "return /pat/.test()"
47
48 while (pos >= 0){
49 var key_q = str.charAt(pos);
50 var key_c = str.substr(pos,2);
51 var key_r = last + key_c;
52
53 if((pos>6)&&(str.substr(pos-6,6)=="return")&&(/^[\s\n]*\/[^\/\*]/.test(str.substring(pos,LEN))))retrn=true;
54
55 if (key_q=="'") { arg = 0; pos++; } //find pos of keyword '
56 else if (key_q=='"') { arg = 1; pos++; } //find pos of keyword "
57 else if ((key_q=='/') && (key_c!="//") && (key_c!="/*") && ((chr.test(last) || (retrn))))
58 { arg = 4; pos++; } //find pos of keyword /
59 else if (key_c=="//") { arg = 2; pos+=2; } //find pos of keyword //
60 else if (key_c=="/*") { arg = 3; pos+=2; } //find pos of keyword /*
61 else { arg =-1; pos++; }
62
63 if (arg>=0){ //if keyword is found
64
65 if (arg==0) { temp=(str.substring(pos-1, LEN).replace(/\\\\|\\\"/g,"xx")); end = temp.search(s_q)+pos; temp=null;}
66 else if (arg==1) { temp=(str.substring(pos-1, LEN).replace(/\\\\|\\\'/g,"xx")); end = temp.search(d_q)+pos; temp=null;}
67
68 else if (arg==4) { var eol = str.indexOf("\n", pos); // find end of line
69 if(eol==-1){return(CODE+"\nerror : no end of line");}
70 var temp = next = (str.substring(pos-1,eol+2).replace(/\\\\/g,"xx")); // end+2 ==> \n
71 end = 0; var t_l=temp.length-2; retrn=false;
72
73 while(end<t_l-1){ //(str.substring(pos-1,end+1))==> /pat/
74
75 var isReg=true;
76
77 next=(temp.substring(end,t_l+1)); // store temp to next
78
79 end=parseInt(end+next.search(Exp)+2); //alert("next="+next); //find next key /
80
81 try{ eval(temp.substring(0,end));}catch(e){isReg=false; var err=(e);}
82
83 if(isReg) break;
84 }
85
86 end=parseInt(end+pos-2); temp=null; next=null;
87
88 if(!(isReg)){bracket[3]+=err+" : "+(str.substring(pos-1,end+1))+" pos ="+pos;}
89 }
90
91 else if (arg==2) { end = str.indexOf("\n", pos); pos--; cmt = true; }
92
93 else /*arg==3*/ { end = str.indexOf("*/", pos); pos--; end++; //pos-- because 2 char "/*"
94 if (end == 0) cmt = false; //if not found(avoid error)
95 else cmt = true; }
96
97 if (end <= 0) end=str.length-1; end++;
98
99 if (cmt==false) CODE += str.substring(pos-1,end);//alert(str.substring(pos-1,end+1));
100
101 pos=end; //if(arg==4) pos++; // end=pos at "/" so add 1
102
103 cmt=false; //at last, end up with pos=0
104
105 }else{ // else keyword is not found
106
107 if((last==";") && (key_q=="}")){ key_q="/**/"; bracket[1]--;} //replace(/\;\}/g,"}");
108
109 if (!(Reg.test(key_r))) { CODE += key_q; last=key_q;}
110
111 switch(key_q){
112 case "(" : bracket[0]++; break;
113 case ")" : bracket[0]--; break;
114 case "{" : bracket[1]++; break;
115 case "}" : bracket[1]--; break;
116 case "[" : bracket[2]++; break;
117 case "]" : bracket[2]--;
118 }
119 if(pos>=str.length) pos=-1;
120 }
121 }
122 str=null;
123
124 CODE=CODE.replace(/^\s+/,"").replace(/[\s\n]*$/,"").replace(/\;\/\*\*\//g,"}");
125
126 var j=CODE.length;
127 var el=$id("ratio");//el.style.backgroundColor="#000";
128 el.innerHTML="Compression Ratio:"+j+"/"+Size+"="+eval(j/Size).toFixed(5);
129
130 var hr ="\n/*------------------------------------\n";
131 var hr2="\n------------------------------------*/\n";
132
133 if (eval(bracket[0]+bracket[1]+bracket[2])!=0)
134 CODE+=hr+"Check pair of brackets. \n () :"+bracket[0]+"; {} :"+bracket[1]+"; [] : "+bracket[2]+hr2;
135 if (bracket[3]!="")
136 CODE+=hr+"Check Syntax of RegExp. \n"+(bracket[3]).replace(/xx/g,"\\\\")+hr2;
137
138 return(CODE);
139 }
140
Modified on 29 Sep. 2008
1 /****************************************************************
2 2008 (C)samurai-logic.com
3
4
5 Javascript Compressor
6
7 Last Modified 29 Sep. 2008
8 ****************************************************************/
9 function $compress(str){
10
11 var Size=str.length;
12
13 //if(/\n/g.test(str)) return("no end of line");
14
15 str=str.replace(/\t+/g," ");
16
17 Reg=/([^\d\w]\n[^\d\w]|[^\d\w]\s[^\d\w]|[\d\w]\s[^\d\w\$\_\#]|[^\d\w]\s[\d\w])/;
18
19 //Exp=/[^\\]\/[^\/]*([\s\,\;]*)((\,\s*(\"|\')|(\w+)\s*\(\s*\/*)[\s\S]+|\/\/[\s\S]+|\/\*[\s\S]+|\s{2,}[\s\S]+|\s*)\n*/;
20 //Exp=/[^\\]\/([^\/])?(\s)*(([\,\s]*(\"|\')|(\w+)\s*\(\s*\/*)[\s\S]+|\/\/[\s\S]+|\/\*[\s\S]+|\s{2,}[\s\S]+|\s*)\n*/;
21
22 //Basic Exp
23 Exp=/[^\\]\/([^\/])/;
24
25 chr=/(\(|\=|\[|\:|\||\&|\!|\,)/; // new reg
26
27 //these RegExp don't need to replace(/\\\\/g,"xx")...but just in case.
28 d_q=/([^\\]\"[^\"]*[^\:]|[^\"]\"[\s]*[\:\,\}\]\)\;\.])/;
29 s_q=/([^\\]\'[^\']*[^\:]|[^\']\'[\s]*[\:\,\}\]\)\;\.])/;
30
31 // Basic RegExp
32 //d_q=/([^\\]\"|[^\"]\")/;
33 //s_q=/([^\\]\'|[^\']\')/;
34
35 bracket=new Array();
36
37 bracket[0]=0; bracket[1]=0; bracket[2]=0; bracket[3]="";
38
39 var CODE = ""; //new string for compressed code
40 var cmt = false; //cmt=true, char is comment.< -- > cmt=false, char is code.
41 var arg = -1; //arg decide the keyword to find
42 var pos = end = 0; //pos = postion of open keyword, end = postion of close keyword
43 var last=" "; //last is last char which store to CODE
44 var temp=""; //temp is to find another keyword
45 var LEN=str.length;
46 var retrn = false; // for regexp "return /pat/.test()"
47
48 /*-----------------------------------------------
49 While loop begin. check each char in string
50 ------------------------------------------------*/
51 while (pos >= 0){
52 var key_q = str.charAt(pos); //keyword quot
53 var key_c = str.substr(pos,2); //keyword comment
54 var key_r = last + key_c; //keyword to test key_q is necessary
55
56 if((pos>6)&&(str.substr(pos-6,6)=="return")&&(/^[\s\n]*\/[^\/\*]/.test(str.substring(pos,LEN))))retrn=true;
57
58 if (key_q=="'") { arg = 0; pos++; } //find pos of keyword '
59 else if (key_q=='"') { arg = 1; pos++; } //find pos of keyword "
60 else if ((key_q=='/') && (key_c!="//") && (key_c!="/*") && ((chr.test(last) || (retrn))))
61 { arg = 4; pos++; } //find pos of keyword /
62 else if (key_c=="//") { arg = 2; pos+=2; } //find pos of keyword //
63 else if (key_c=="/*") { arg = 3; pos+=2; } //find pos of keyword /*
64 else { arg =-1; pos++; }
65
66 if (arg>=0){ //if keyword is found
67
68 if (arg==0) { temp=(str.substring(pos-1, LEN)); end = temp.search(s_q)+pos; temp=null;}
69 else if (arg==1) { temp=(str.substring(pos-1, LEN)); end = temp.search(d_q)+pos; temp=null;}
70
71 else if (arg==4) { var eol = str.indexOf("\n", pos); // find end of line
72 if(eol==-1){return(CODE+"\nerror : no end of line");}
73 var temp = next = (str.substring(pos-1,eol+2).replace(/\\\\/g,"xx")); // end+2 ==> \n
74 end = 0; var t_l=temp.length-2; retrn=false;
75
76 /*---------------------------------------------------------------
77 loop to find next keyword "/" and evaluate Regular Expression
78 and if RegExp is NG, store error message to var err.
79 ----------------------------------------------------------------*/
80
81 while(end<t_l-1){
82
83 var isReg=true;
84
85 next=(temp.substring(end,t_l+1)); // store temp to next
86
87 end=parseInt(end+next.search(Exp)+2); //alert("next="+next); //find next key /
88
89 try{ eval(temp.substring(0,end));} //evaluate RegExp
90 catch(e){isReg=false; var err=(e);}// store error msg to err
91
92 if(isReg) break;//if RegExp is OK, then break
93 }
94
95 end=parseInt(end+pos-2); temp=null; next=null; //add pos to end, and release memory
96
97 if(!(isReg)){bracket[3]+=err+" : "+(str.substring(pos-1,end+1))+" pos ="+pos;}
98 }
99
100 else if (arg==2) { end = str.indexOf("\n", pos); pos--; cmt = true; }
101
102 else /*arg==3*/ { end = str.indexOf("*/", pos); pos--; end++; //pos-- because 2 char "/*"
103 if (end == 0) cmt = false; //if not found(avoid error)
104 else cmt = true; }
105
106 if (end <= 0) end=str.length-1; end++;
107
108 if (cmt==false) CODE += str.substring(pos-1,end);//alert(str.substring(pos-1,end+1));
109
110 pos=end; //if(arg==4) pos++; // end=pos at "/" so add 1
111
112 cmt=false; //at last, end up with pos=0
113
114 }else{ // else keyword is not found
115
116 if((last==";") && (key_q=="}")){ key_q="/**/"; bracket[1]--;} //replace(/\;\}/g,"}");
117
118 if (!(Reg.test(key_r))) { CODE += key_q; last=key_q;}
119
120 switch(key_q){
121 case "(" : bracket[0]++; break;//in case ( is found then count one
122 case ")" : bracket[0]--; break;
123 case "{" : bracket[1]++; break;
124 case "}" : bracket[1]--; break;
125 case "[" : bracket[2]++; break;
126 case "]" : bracket[2]--;
127 }
128 if(pos>=str.length) pos=-1;
129 }
130 } //while loop
131 str=null;
132
133 CODE=CODE.replace(/^\s+/,"").replace(/[\s\n]*$/,"").replace(/\;\/\*\*\//g,"}");
134
135 var j=CODE.length;
136 var el=$id("ratio");//el.style.backgroundColor="#000";
137 el.innerHTML="Compression Ratio:"+j+"/"+Size+"="+eval(j/Size).toFixed(5);
138
139 var hr ="\n/*------------------------------------\n";
140 var hr2="\n------------------------------------*/\n";
141
142 if (eval(bracket[0]+bracket[1]+bracket[2])!=0)
143 CODE+=hr+"Check pair of brackets. \n () :"+bracket[0]+"; {} :"+bracket[1]+"; [] : "+bracket[2]+hr2;
144 if (bracket[3]!="")
145 CODE+=hr+"Check Syntax of RegExp. \n"+(bracket[3]).replace(/xx/g,"\\\\")+hr2;
146
147 return(CODE);
148 }
149