前沿拓展:
命令行選項(xiàng)語(yǔ)法錯(cuò)誤
命令行的意思是按住winkey+R鍵,彈出的運(yùn)行中輸入CMD,確定后跳出一個(gè)黑色窗口,這就是命令行。
命令行里有許多命令,有的是系統(tǒng)自帶,有的是下載的。你可以輸入命令/?查看如何用這個(gè)命令。
比如輸入 del/?,就會(huì)出現(xiàn)del這個(gè)命令的用法。
命令行選項(xiàng)語(yǔ)法錯(cuò)誤,就是命令用錯(cuò)了。彈出來關(guān)掉就好了。
本文,將實(shí)現(xiàn)命令行輸出帶有語(yǔ)法高亮、帶行號(hào)的JS代碼。
效果如下圖所示:
對(duì)于JS程序員而言,這個(gè)效果是有些驚喜的。
而實(shí)現(xiàn)起來,卻似乎是出乎意料的簡(jiǎn)單。
直接上源碼:
var js_code = `
function get_copyright(){
var domain = "jshaman.com";
var from_year = 2017;
var copyright = "(c)" + from_year + "-" + (new Date).getFullYear() + "," + domain;
return copyright;
}
console.log(get_copyright());
`;
//高亮顯示代碼
const { codeFrameColumns } = require('@babel/code-frame');
const res = codeFrameColumns(js_code, {}, {
highlightCode: true,
});
console.log(res);
由代碼可見,僅僅是使用@babel/code-frame這個(gè)NodeJS模塊即可直接實(shí)現(xiàn)高亮語(yǔ)法。
本著“知其然,知其所以然”的理念,我們?cè)偕钊胩骄恳幌聦?shí)現(xiàn)語(yǔ)法高亮的原理。
第一,是進(jìn)行語(yǔ)法分析,從JS代碼分離出不同的關(guān)鍵字。
在這一步,可以使用babel的parser獲得代碼的AST(抽象語(yǔ)法樹),再遍歷AST進(jìn)行分析取詞。
例如獲得變量名、函數(shù)名的方式如下:
var parser = require('@babel/parser');
var traverse = require('@babel/traverse').default;
//獲得抽象語(yǔ)法樹
var ast = parser.parse(js_code);
//遍歷語(yǔ)法樹
traverse(ast, traverse(ast,{
//函數(shù)
"FunctionDeclaration"(path){
var fun_name = path.node.id.name;
console.log("函數(shù)名:",fun_name);
},
//變量
"VariableDeclaration"(path){
var var_name = path.node.declarations[0].id.name;
console.log("變量名:",var_name);
},
}));
console.log(js_code)
注:語(yǔ)法分析也有其它辦法,比如用正則等。
接著上面的思路,當(dāng)獲得變量名、函數(shù)名之后,接下來即可對(duì)其進(jìn)行著色。
寫著色功能之前,先來看行代碼:
console.log('u001b[31m JShaman專注于JS代碼混淆加密 u001b[0m');
它會(huì)輸出帶顏色的信息,如下圖:
為什么看似有些亂碼的console執(zhí)行時(shí)會(huì)出現(xiàn)彩色的文字呢?
解釋是這樣的:
The original specification only had 8 colors, and just gave them names. The SGR parameters 30-37 selected the foreground color, while 40-47 selected the background. Quite a few terminals implemented "bold" (SGR code 1) as a brighter color rather than a different font, thus providing 8 additional foreground colors. Usually you could not get these as background colors, though sometimes inverse video (SGR code 7) would allow that. Examples: to get black letters on white background use ESC[30;47m, to get red use ESC[31m, to get bright red use ESC[31;1m. To reset colors to their defaults, use ESC[39;49m (not supported on some terminals), or reset all attributes with ESC[0m.
大意是:“u001b”是一個(gè)特殊的轉(zhuǎn)意字符,遵從一定的規(guī)則,可以用來設(shè)置文字或背景顏色。
上面代碼中,前面的u001b[31m用于設(shè)定SGR顏色,后面的u001b[0m相當(dāng)于一個(gè)封閉標(biāo)簽作為前面SGR顏色的作用范圍的結(jié)束點(diǎn)標(biāo)記。
有了這個(gè)知識(shí)儲(chǔ)備后,我們就可以繼續(xù)前面的工作。
當(dāng)從JS代碼中進(jìn)行分詞之后,將代碼用此方法進(jìn)行改造,即可使語(yǔ)法高亮。
運(yùn)行效果:
至此,便已得知了命令行語(yǔ)法高亮的全部秘密。
最后,奉上本示例完整源碼:
var js_code = `
function demo(){
var domain = "jshaman.com";
var from_year = 2017;
var copyright = "(c)" + from_year + "-" + (new Date).getFullYear() + "," + domain;
return copyright;
}
console.log(demo());
`;
//高亮顯示代碼
const { codeFrameColumns } = require('@babel/code-frame');
const res = codeFrameColumns(js_code, {}, {
highlightCode: true,
});
console.log(res);
var parser = require('@babel/parser');
var traverse = require('@babel/traverse').default;
//獲得抽象語(yǔ)法樹
var ast = parser.parse(js_code);
//遍歷語(yǔ)法樹
traverse(ast, traverse(ast,{
//函數(shù)
"FunctionDeclaration"(path){
var fun_name = path.node.id.name;
console.log("函數(shù)名:",fun_name);
js_code = js_code.replace(fun_name,"u001b[32m" + fun_name + "u001b[0m");
},
//變量
"VariableDeclaration"(path){
var var_name = path.node.declarations[0].id.name;
console.log("變量名:",var_name);
js_code = js_code.replace(var_name,"u001b[31m" + var_name + "u001b[0m");
},
}));
console.log(js_code)
JavaScript奇淫技巧:按鍵精靈
JavaScript奇淫技巧:收縮控制流
JavaScript奇淫技巧:變速齒輪
JavaScript奇淫技巧:隱寫術(shù)
JavaScript奇淫技巧:壓縮并加密圖片
JavaScript奇淫技巧:用try、catch實(shí)現(xiàn)JS代碼加密解密
拓展知識(shí):
命令行選項(xiàng)語(yǔ)法錯(cuò)誤
安裝時(shí)可能會(huì)遇到其他軟件占用某個(gè)安裝可能會(huì)修改或占用的程序而造成的,或者是殺毒軟件或防火墻所造成的,你只要試著在安裝時(shí)關(guān)閉其他程序再安裝一遍應(yīng)該就可以了。
原創(chuàng)文章,作者:九賢生活小編,如若轉(zhuǎn)載,請(qǐng)注明出處:http://xiesong.cn/22101.html