国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > JavaScript > 正文

js 玩轉正則表達式之語法高亮

2020-03-22 20:25:49
字體:
來源:轉載
供稿:網友
學了幾天正則,差不多該總結整理寫成果了,之前就想寫語法高亮匹配來著,不過水平不夠,看著例子都不理解。那么我們來分析下兩位大神 次碳酸鈷 和 Barret Lee 語法高亮實現。先說 Barret Lee 的這篇 《幾個小例子教你如何實現html' target='_blank'>正則表達式highlight高亮》之前看的時候只覺的神奇,特別是下面那個一步一步分開匹配的例子,更是霸氣測漏,不過作者也說了,分開只是為了演示方便,可以很直觀的看到這一步匹配了什么,不然一步到位匹配完成,你都不知道發生了什么就處理完畢了。
來看下他的正則如何實現正則表達式的JavaScript的代碼高亮》
其實這篇已經分析的非常詳細了,我只能簡單補充說明下。
次碳酸鈷 思維一向比較嚴謹,這篇文章之前我看了一個多小時,只能看個大概,這次重新分析了一遍,然后自己實現了一遍,竟然也花去我半天時間,
不過非常值得,真心學到了很多。先來看一下大體的邏輯吧。復制代碼 代碼如下:
(////.*|///*[/S/s]+?/*//) // 匹配注釋
((["'])(?://.|[^///n])*?/3) // 匹配字符串
/b(break|continue|do|for|in|function|if|else|return|switch|this|throw|try|catch|finally|var|while|with|case|new|typeof|instance|delete|void)/b // 匹配關鍵詞
/b(Object|Array|String|Number|Boolean|Function|RegExp|Date|Math|window|document|navigator|location)/b // 匹配內置對象
/b(true|false)/b // 匹配布爾值
/b(null|undefined|NaN)/b // 匹配各種空值, 我覺得這個和布爾值一組比較合適。
(?:[^/W/d]|/$)[/$/w]* // 匹配普通的變量名
(0[xX][0-9a-fA-F]+|/d+(?:/./d+)?(?:[eE]/d+)?) // 匹配數字 (前者不占用,這里就會有問題)
(?:[^/)/]/}]|^)(//(?!/*)(?://.|[^/////n])+?//[gim]*) // 匹配正則
[/S/s] // 其他不能匹配的任意值
原文對最后一個 [/S/s] 的描述:我們必須匹配到每一個字符。因為它們都需要做一次HTML轉義。
然后下面有詳細的代碼。這是一篇非常不錯的文章,我前前后后至少看了不下10次了,前兩天才差不多完全明白。不過這個代碼還有一些小小的瑕疵,比如字符串不能匹配折行那種,字符串匹配優化。還有數字匹配不夠全面只能匹配 0xff, 12.34, 1e3 這幾類,如 .123 12.3e+3 等格式都無法匹配到。
還有關鍵詞順序我覺得可以稍微優化下。
因為 傳統型NFA 引擎的只是從左往右匹配,匹配到了就停止下一個分支的操作。
所以把最常出現的關鍵詞放前面,可以提升一部分性能。
最后,最好是 new RegExp 這樣對于代碼量大的代碼性能上會有所提升。下面就給出我的正則和簡單的demo吧。(其實只是對 次碳酸鈷 源碼的優化而已。。)
先來看正則部分:復制代碼 代碼如下:
(////.*|///*[/s/S]*?/*//) // 匹配注釋 沒改
("(?:[^"http://]|//[/s/S])*"|'(?:[^'//]|//[/s/S])*') // 匹配注釋 優化過
/b(true|false|null|undefined|NaN)/b // 匹配 布爾和空值,這幾個比較常用,分組提前
/b(var|for|if|else|return|this|while|new|function|switch|case|typeof|do|in|throw|try|catch|finally|with|instance|delete|void|break|continue)/b // 匹配關鍵詞,關鍵詞順序改了下
/b(document|Date|Math|window|Object|location|navigator|Array|String|Number|Boolean|Function|RegExp)/b //內置對象,單詞順序改了下
(?:[^/W/d]|/$)[/$/w]* // 匹配普通的變量名 沒改
(0[xX][0-9a-fA-F]+|/d+(?:/./d+)?(?:[eE][+-]?/d+)?|/./d+(?:[eE][+-]?/d+)?) // 匹配數字,修復了匹配
(?:^|[^/)/]/}])(//(?!/*)(?://.|[^/////n])+?//[gim]*) // 匹配正則,這個最復雜,情況很多,我暫時沒實力修改
[/s/S] // 匹配其他
合并了布爾和空值一個分組,然后優化了正則分組,所以比他減少了2個分組。
他 2,3 是字符串分組,因為 (["']) 捕獲了前面的引號,而我的正則沒這么做。
這個 (true|false|null|undefined|NaN) 如果你不喜歡放在一個分組了,分開也行、
是不是同一個分組,只是為了區分著色而已。
sublime text 下 true|false|null|undefined|NaN 都是一個顏色,而 notepad++ 則只著色了 true|false ,我只想說 呵呵。好了,差不多該給例子了。
我相信,不少人在看到這之前已經關掉了,或者只是拉了下滾動條然后關掉了。
不過我寫這個就是為了給這些認真看下來的朋友,只要有一個人看,我覺得就不會白寫了。
例子:復制代碼 代碼如下:
// 單行注釋
/**
* 多行注釋
* @date 2014-05-12 22:24:37
* @name 測試一下
*/
var str1 = "123/"456";
var str2 = '123/'456';
var str3 = "123/
456";var num = 123;
var arr = [12, 12.34, .12, 1e3, 1e+3, 1e-3, 12.34e3, 12.34e+3, 12.34e-3, .1234e3];
var arr = ["12", "12.34", '.12, 1e3', '1e+3, 1e-3', '12.34e3, 12.34e+3, 12.34e-3', ".1234e3"];
var arr = [/12", "12.34/, /"12//34"/];for (var i=0; i i++) {
var node = document.getElementById("a"+i);
arr.push(node);
}function test () {
return true;
}
test();(function(window, undefined) {
var _re_js = new RegExp('(//////.*|/////*[//s//S]*?//*///)|("(?:[^"http:////]|////[//s//S])*"|/'(?:[^/'////]|////[//s//S])*/')|//b(true|false|null|undefined|NaN)//b|//b(var|for|if|else|return|this|while|new|function|switch|case|typeof|do|in|throw|try|catch|finally|with|instance|delete|void|break|continue)//b|//b(document|Date|Math|window|Object|location|navigator|Array|String|Number|Boolean|Function|RegExp)//b|(?:[^//W//d]|//$)[//$//w]*|(0[xX][0-9a-fA-F]+|//d+(?://.//d+)?(?:[eE][+-]?//d+)?|//.//d+(?:[eE][+-]?//d+)?)|(?:^|[^//)//]//}])(///(?!//*)(?:////.|[^/////////n])+?///[gim]*)|[//s//S]', 'g'); function prettify(node) {
var code = node.innerHTML.replace(//r/n|[/r/n]/g, "/n").replace(/^/s+|/s+$/g, "");
code = code.replace(_re_js, function() {
var s, a = arguments;
for (var i = 1; i i++) {
if (s = a[i]) {
s = htmlEncode(s);
switch (i) {
case 1: //注釋 com
return ' span ' + s + ' /span
case 2: //字符串 str
return ' span ' + s + ' /span
case 3: //true|false|null|undefined|NaN val
return ' span ' + s + ' /span
case 4: //關鍵詞 kwd
return ' span ' + s + ' /span
case 5: //內置對象 obj
return ' span ' + s + ' /span
case 6: //數字 num
return ' span ' + s + ' /span
case 7: //正則 reg
return htmlEncode(a[0]).replace(s, ' span ' + s + ' /span
}
}
}
return htmlEncode(a[0]);
});
code = code.replace(/(?:/s*/*/s*|(?: )*/*(?: )*)(@/w+)/b/g, ' * span $1 /span ') // 匹配注釋中的標記
.replace(/(/w+)(/s*/(|(?: )*/()|(/w+)(/s*=/s*function|(?: )*=(?: )*function)/g, ' span $1 /span $2') // 匹配函數
return code;
}
function htmlEncode(str) {
var i, s = {
//"&": /&/g,
""": /"/g,
"'": /'/g,
" ": //g,
" br ": //n/g,
" ": / /g,
" ": //t/g
};
for (i in s) {
str = str.replace(s[i], i);
}
return str;
} window.prettify = prettify;
})(window);
你們可以用下面的代碼進行測試。代碼:復制代碼 代碼如下:
!doctype html
html lang="en"
head
meta charset="UTF-8"
title test /title
style
/* 高亮樣式 */
*{font-size:12px;}
code{word-break:break-all;} .com {color:#008000;} /* 注釋 */
.comkey {color:#FFA500;} /* 注釋標記 */
.str {color:#808080;} /* 字符串 */
.val {color:#000080;} /* true|false|null|undefined|NaN */
.kwd {color:#000080;font:bold 12px 'comic sans ms', sans-serif;} /* 關鍵詞 */
.obj {color:#000080;} /* 內置對象 */
.num {color:#FF0000;} /* 數字 */
.reg {color:#8000FF;} /* 正則 */
.func {color:#A355B9;} /* 函數 */
/style
/head
body code id="regdemon"
// 單行注釋
/**
* 多行注釋
* @date 2014-05-12 22:24:37
* @name 測試一下
*/
var str1 = "123/"456";
var str2 = '123/'456';
var str3 = "123/
456";var num = 123;
var arr = [12, 12.34, .12, 1e3, 1e+3, 1e-3, 12.34e3, 12.34e+3, 12.34e-3, .1234e3];
var arr = ["12", "12.34", '.12, 1e3', '1e+3, 1e-3', '12.34e3, 12.34e+3, 12.34e-3', ".1234e3"];
var arr = [/12", "12.34/, /"12//34"/];for (var i=0; i i++) {
var node = document.getElementById("a"+i);
arr.push(node);
}function test () {
return true;
}
test();(function(window, undefined) {
var _re_js = new RegExp('(//////.*|/////*[//s//S]*?//*///)|("(?:[^"http:////]|////[//s//S])*"|/'(?:[^/'////]|////[//s//S])*/')|//b(true|false|null|undefined|NaN)//b|//b(var|for|if|else|return|this|while|new|function|switch|case|typeof|do|in|throw|try|catch|finally|with|instance|delete|void|break|continue)//b|//b(document|Date|Math|window|Object|location|navigator|Array|String|Number|Boolean|Function|RegExp)//b|(?:[^//W//d]|//$)[//$//w]*|(0[xX][0-9a-fA-F]+|//d+(?://.//d+)?(?:[eE][+-]?//d+)?|//.//d+(?:[eE][+-]?//d+)?)|(?:^|[^//)//]//}])(///(?!//*)(?:////.|[^/////////n])+?///[gim]*)|[//s//S]', 'g'); function prettify(node) {
var code = node.innerHTML.replace(//r/n|[/r/n]/g, "/n").replace(/^/s+|/s+$/g, "");
code = code.replace(_re_js, function() {
var s, a = arguments;
for (var i = 1; i i++) {
if (s = a[i]) {
s = htmlEncode(s);
switch (i) {
case 1: //注釋 com
return ' span ' + s + ' /span
case 2: //字符串 str
return ' span ' + s + ' /span
case 3: //true|false|null|undefined|NaN val
return ' span ' + s + ' /span
case 4: //關鍵詞 kwd
return ' span ' + s + ' /span
case 5: //內置對象 obj
return ' span ' + s + ' /span
case 6: //數字 num
return ' span ' + s + ' /span
case 7: //正則 reg
return htmlEncode(a[0]).replace(s, ' span ' + s + ' /span
}
}
}
return htmlEncode(a[0]);
});
code = code.replace(/(?:/s*/*/s*|(?:)*/*(?:)*)(@/w+)/b/g, '* span $1 /span ') // 匹配注釋中的標記
.replace(/(/w+)(/s*/(|(?:)*/()|(/w+)(/s*=/s*function|(?:)*=(?:)*function)/g, ' span $1 /span $2') // 匹配函數
return code;
}
function htmlEncode(str) {
var i, s = {
//" ": /&/g,
" ": /"/g,
" ": /'/g,
" ": / /g,
" ": / /g,
" br ": //n/g,
"": / /g,
"": //t/g
};
for (i in s) {
str = str.replace(s[i], i);
}
return str;
} window.prettify = prettify;
})(window);
/code script
(function(window, undefined) {
var _re_js = new RegExp('(//////.*|/////*[//s//S]*?//*///)|("(?:[^"http:////]|////[//s//S])*"|/'(?:[^/'////]|////[//s//S])*/')|//b(true|false|null|undefined|NaN)//b|//b(var|for|if|else|return|this|while|new|function|switch|case|typeof|do|in|throw|try|catch|finally|with|instance|delete|void|break|continue)//b|//b(document|Date|Math|window|Object|location|navigator|Array|String|Number|Boolean|Function|RegExp)//b|(?:[^//W//d]|//$)[//$//w]*|(0[xX][0-9a-fA-F]+|//d+(?://.//d+)?(?:[eE][+-]?//d+)?|//.//d+(?:[eE][+-]?//d+)?)|(?:^|[^//)//]//}])(///(?!//*)(?:////.|[^/////////n])+?///[gim]*)|[//s//S]', 'g'); function prettify(node) {
var code = node.innerHTML.replace(//r/n|[/r/n]/g, "/n").replace(/^/s+|/s+$/g, "");
code = code.replace(_re_js, function() {
var s, a = arguments;
for (var i = 1; i i++) {
if (s = a[i]) {
s = htmlEncode(s);
switch (i) {
case 1: //注釋 com
return ' span ' + s + ' /span
case 2: //字符串 str
return ' span ' + s + ' /span
case 3: //true|false|null|undefined|NaN val
return ' span ' + s + ' /span
case 4: //關鍵詞 kwd
return ' span ' + s + ' /span
case 5: //內置對象 obj
return ' span ' + s + ' /span
case 6: //數字 num
return ' span ' + s + ' /span
case 7: //正則 reg
return htmlEncode(a[0]).replace(s, ' span ' + s + ' /span
}
}
}
return htmlEncode(a[0]);
});
code = code.replace(/(?:/s*/*/s*|(?:)*/*(?:)*)(@/w+)/b/g, '* span $1 /span ') // 匹配注釋中的標記
.replace(/(/w+)(/s*/(|(?:)*/()|(/w+)(/s*=/s*function|(?:)*=(?:)*function)/g, ' span $1 /span $2') // 匹配函數
return code;
}
function htmlEncode(str) {
var i, s = {
//" ": /&/g,
" ": /"/g,
" ": /'/g,
" ": / /g,
" ": / /g,
" br ": //n/g,
"": / /g,
"": //t/g
};
for (i in s) {
str = str.replace(s[i], i);
}
return str;
} window.prettify = prettify;
})(window);var code = document.getElementById("regdemon");
code.innerHTML = prettify(code);
/script
/body
/html
差不多結合了 小胡子哥 和 次碳酸鈷 兩個思路的結果,現在比較完善了。
兼容什么的還沒測試,也沒必要測試了,我也沒打算自己寫各種語法的高亮,太TM累了。。PHP教程

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 九龙县| 葫芦岛市| 丰原市| 龙江县| 清流县| 增城市| 富源县| 克山县| 邵阳市| 抚州市| 广昌县| 仲巴县| 盐城市| 扶沟县| 新邵县| 郧西县| 城口县| 承德县| 保定市| 吉安市| 大英县| 大新县| 揭阳市| 定远县| 阿拉善左旗| 手游| 康保县| 大理市| 菏泽市| 康平县| 黎平县| 南川市| 阿拉善左旗| 葵青区| 讷河市| 康保县| 小金县| 陆丰市| 五常市| 赣州市| 吉安县|