Shell 压缩或解压缩JavaScript,JavaScript广泛用于网站设计。在编写JavaScript代码时,出于代码可读性以及可维护性方面的考虑,我们会使用一些空格、注释和制表符。但这些内容会增加JavaScript文件的体积,拖慢页面的加载速度。因此,多数专业网站为了加快页面载入速度,都会压缩JavaScript文件。这多是通过删除空白字符和换行符来实现的(也被称为minified JS)。对于压缩过的JavaScript,还可以通过加入足够的空白字符和换行符解压缩,恢复代码的可读性。本章就尝试在shell中实现类似的功能。
预备知识
我们准备写一个JavaScript压缩工具,当然,还包括与之对应的解压缩工具。来考虑下面的Javascript代码:
$ cat sample.js
function sign_out()
{
$("#loading").show();
$.get("log_in",{logout:"True"},
function(){
window.location="";
});
}
下面是压缩JavaScript代码所需要完成的工作。
(1) 移除换行符和制表符。
(2) 移除重复的空格。
(3) 替换掉注释/* content */
。
要解压缩或者恢复JavaScript代码的可读性,则需要:
- 用
;\n
替换;
; - 用
{\n
替换{
,\n}
替换}
。
实战演练
按照之前叙述过的步骤,我们使用下面的命令序列:
$ cat sample.js | \
tr -d '\n\t' | tr -s ' ' \
| sed 's:/\*.*\*/::g' \
| sed 's/ \?\([{}();,:]\) \?/\1/g'
输出如下:
function sign_out(){("#loading").show();.get("log_in",
{logout:"True"}, function(){window.location="";});}
接着写一个可以将这些混乱的代码恢复正常的解压缩脚本:
$ cat obfuscated.txt | sed 's/;/;\n/g; s/{/{\n\n/g; s/}/\n\n}/g'
或者
$ cat obfuscated.txt | sed 's/;/;\n/g' | sed 's/{/{\n\n/g' | sed
's/}/\n\n}/g'
该脚本在使用上存在局限:它会删除本不该删除的空格。假如有下列语句:
var a = "hello world"
两个空格会被转换成一个。这种问题可以使用我们讲过的模式匹配工具来解决。另外,如果需要处理关键JavaScript代码,最好还是使用功能完善的工具来实现。
工作原理
通过执行下面的步骤来进行压缩。
(1) 移除\n
和\t
:
tr -d '\n\t'
(2) 移除多余的空格:
tr -s ' '
或者
sed 's/[ ]\+/ /g'
(3) 移除注释:
sed 's:/\*.*\*/::g'
因为我们需要使用/*
和*/
,所以用:
作为sed
的分隔符,这样就不必对 /
进行转义了。
*
在 sed
中被转义为\*
。
.*
用来匹配/*
与*/
之间所有的文本。
(4) 移除{,}
、(,)
、;
、:
以及,
前后的空格:
sed 's/ \?\([{}();,:]\) \?/\1/g'
上面的sed
语句含义如下。
/ \?\([{}();,:]\) \?/
用于匹配,/\1/g
用于替换。\([{}();,:]\)
用于匹配字符组[ { }( ) ; , : ]
(出于可读性方面的考虑,在这里加入了空格)中的任意一个字符。\(
和\)
是分组操作符,用于记忆所匹配的内容,以便在替换部分中进行向后引用。对(
和)
转义之后,它们便具备了另一种特殊的含义,可以作为分组操作符使用。位于分组操作符前后的\?
用来匹配可能出现在字符集合周围的空格。- 在命令的替换部分,匹配的字符串(也就是一个可选的空格、一个来自字符集的字符再加一个可选的空格)被匹配的子串所替换。由分组操作符匹配到并记忆的子串是通过向后引用来指代的。可以用符号
\1
向后引用该分组所匹配的内容。
解压缩命令的工作方式如下:
s/;/;\n/g
将;
替换为;\n
;s/{/{\n\n/g
将{
替换为{\n\n
;s/}/\n\n}/g
将}
替换为\n\n}
。
学习本章内容可以参考sed 命令 和 tr 命令 相关知识。