亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > regex > 正文

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

2020-01-20 22:12:12
字體:
來源:轉載
供稿:網友

學了幾天正則,差不多該總結整理寫成果了,之前就想寫語法高亮匹配來著,不過水平不夠,看著例子都不理解。

那么我們來分析下兩位大神 次碳酸鈷 和 Barret Lee 語法高亮實現。

先說 Barret Lee 的這篇 《幾個小例子教你如何實現正則表達式highlight高亮

之前看的時候只覺的神奇,特別是下面那個一步一步分開匹配的例子,更是霸氣測漏,不過作者也說了,分開只是為了演示方便,可以很直觀的看到這一步匹配了什么,不然一步到位匹配完成,你都不知道發生了什么就處理完畢了。
來看下他的正則

復制代碼 代碼如下:

(/^/s+|/s+$/) // 匹配首尾空格
(/(["'])(?://.|[^///n])*?/1/) // 匹配字符串
(///(?!/*|span).+//(?!span)[gim]*/) // 匹配正則 span 是他上次處理加上的,我覺得這里不應該出現
(/(////.*|///*[/S/s]+?/*//)/) // 匹配注釋
(/(/*/s*)(@/w+)(?=/s*)/) // 匹配 注釋中的標記
(//b(break|continue|do|for|in|function|if|else|return|switch|throw|try|catch|finally|var|while|with|case|new|typeof|instance|delete|void|Object|Array|String|Number|Boolean|Function|RegExp|Date|Math|window|document|navigator|location|true|false|null|undefined|NaN)/b/) // 匹配關鍵詞

小胡子哥可能是不想重復造輪子,只是想弄清楚如何造這樣的輪子而已,所以他寫這個東西點到即止,沒有深入詳細的處理,做的比較粗糙。
當然我也不是說他什么,只是簡單評論一下而已,畢竟優秀的語法高亮插件多的是,沒必要自己重復造,學習下原理即可。

我們再來分析下 次碳酸鈷 這篇 《如何實現正則表達式的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<1e3; 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 <= 7; i++) {
                if (s = a[i]) {
                    s = htmlEncode(s);
                    switch (i) {
                        case 1: //注釋 com
                            return '<span class="com">' + s + '</span>';
                        case 2: //字符串 str
                            return '<span class="str">' + s + '</span>';
                        case 3: //true|false|null|undefined|NaN val
                            return '<span class="val">' + s + '</span>';
                        case 4: //關鍵詞 kwd
                            return '<span class="kwd">' + s + '</span>';
                        case 5: //內置對象 obj
                            return '<span class="obj">' + s + '</span>';
                        case 6: //數字 num
                            return '<span class="num">' + s + '</span>';
                        case 7: //正則 reg
                            return htmlEncode(a[0]).replace(s, '<span class="reg">' + s + '</span>');
                    }
                }
            }
            return htmlEncode(a[0]);
        });
        code = code.replace(/(?:/s*/*/s*|(?: )*/*(?: )*)(@/w+)/b/g, ' * <span class="comkey">$1</span>') // 匹配注釋中的標記
                   .replace(/(/w+)(/s*/(|(?: )*/()|(/w+)(/s*=/s*function|(?: )*=(?: )*function)/g, '<span class="func">$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<1e3; 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 <= 7; i++) {
                if (s = a[i]) {
                    s = htmlEncode(s);
                    switch (i) {
                        case 1: //注釋 com
                            return '<span class="com">' + s + '</span>';
                        case 2: //字符串 str
                            return '<span class="str">' + s + '</span>';
                        case 3: //true|false|null|undefined|NaN val
                            return '<span class="val">' + s + '</span>';
                        case 4: //關鍵詞 kwd
                            return '<span class="kwd">' + s + '</span>';
                        case 5: //內置對象 obj
                            return '<span class="obj">' + s + '</span>';
                        case 6: //數字 num
                            return '<span class="num">' + s + '</span>';
                        case 7: //正則 reg
                            return htmlEncode(a[0]).replace(s, '<span class="reg">' + s + '</span>');
                    }
                }
            }
            return htmlEncode(a[0]);
        });
        code = code.replace(/(?:/s*/*/s*|(?: )*/*(?: )*)(@/w+)/b/g, ' * <span class="comkey">$1</span>') // 匹配注釋中的標記
                   .replace(/(/w+)(/s*/(|(?: )*/()|(/w+)(/s*=/s*function|(?: )*=(?: )*function)/g, '<span class="func">$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 <= 7; i++) {
                if (s = a[i]) {
                    s = htmlEncode(s);
                    switch (i) {
                        case 1: //注釋 com
                            return '<span class="com">' + s + '</span>';
                        case 2: //字符串 str
                            return '<span class="str">' + s + '</span>';
                        case 3: //true|false|null|undefined|NaN val
                            return '<span class="val">' + s + '</span>';
                        case 4: //關鍵詞 kwd
                            return '<span class="kwd">' + s + '</span>';
                        case 5: //內置對象 obj
                            return '<span class="obj">' + s + '</span>';
                        case 6: //數字 num
                            return '<span class="num">' + s + '</span>';
                        case 7: //正則 reg
                            return htmlEncode(a[0]).replace(s, '<span class="reg">' + s + '</span>');
                    }
                }
            }
            return htmlEncode(a[0]);
        });
        code = code.replace(/(?:/s*/*/s*|(?: )*/*(?: )*)(@/w+)/b/g, ' * <span class="comkey">$1</span>') // 匹配注釋中的標記
                   .replace(/(/w+)(/s*/(|(?: )*/()|(/w+)(/s*=/s*function|(?: )*=(?: )*function)/g, '<span class="func">$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累了。。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产91av在线| 国产一区二区美女视频| 91精品国产91久久久| 亚洲精品网站在线播放gif| 97国产suv精品一区二区62| 美女久久久久久久| 亚洲一区第一页| 国产一区二区视频在线观看| 91精品视频在线播放| 91免费观看网站| 亚洲欧洲一区二区三区久久| 丝袜美腿亚洲一区二区| 中文字幕无线精品亚洲乱码一区| 上原亚衣av一区二区三区| 色av吧综合网| 亚洲www视频| 欧美一区二区三区免费观看| 欧美日韩不卡合集视频| 久久精品男人天堂| 美女国内精品自产拍在线播放| 在线精品视频视频中文字幕| 日韩免费av片在线观看| 午夜欧美大片免费观看| 美女999久久久精品视频| 亚洲人a成www在线影院| 91大神福利视频在线| 不卡伊人av在线播放| 韩国视频理论视频久久| 最近2019年日本中文免费字幕| 国产精品视频在线观看| 国产精品无码专区在线观看| 欧美一级淫片videoshd| 91爱爱小视频k| 亚洲一区制服诱惑| 日韩免费黄色av| 亚洲国产精品专区久久| 欧美激情按摩在线| 中文字幕久热精品在线视频| 亚洲欧美综合精品久久成人| 一区二区三区四区视频| 国产精品欧美一区二区| 91在线高清视频| 国产一区二区三区中文| 欧美美女15p| 精品国产成人在线| 精品视频—区二区三区免费| 久久成人av网站| 日韩成人av网| 日韩性生活视频| 日本国产精品视频| 夜夜嗨av色一区二区不卡| 亚洲国产精品嫩草影院久久| 日韩av网站大全| 亚洲网在线观看| 日本亚洲精品在线观看| 国内精品久久久久伊人av| 最好看的2019的中文字幕视频| 精品国产31久久久久久| 久久av在线播放| 国产精品专区第二| 欧美一级免费视频| 国产精品欧美风情| 久久久久久久久综合| 日韩av电影在线免费播放| 欧美精品一区三区| 欧美性在线视频| 欧美日韩国产精品| 日本欧美国产在线| 91免费人成网站在线观看18| 精品久久久在线观看| 成人妇女淫片aaaa视频| 欧美日韩不卡合集视频| 成人免费淫片视频软件| 91香蕉国产在线观看| 欧美最猛黑人xxxx黑人猛叫黄| 伊人男人综合视频网| 欧美性猛交xxxx黑人| 成人黄色在线免费| 红桃视频成人在线观看| 欧美日韩人人澡狠狠躁视频| 伊人久久免费视频| 亚洲va欧美va在线观看| 国产精品亚洲第一区| 欧美激情二区三区| 亚洲成人av在线播放| 国产精品日韩在线一区| 亚洲成avwww人| 中文字幕在线看视频国产欧美在线看完整| 色婷婷综合成人| 国产精品丝袜视频| 欧美日韩国内自拍| 国产精品尤物福利片在线观看| 国产欧美日韩专区发布| 91精品国产高清久久久久久久久| 久久亚洲综合国产精品99麻豆精品福利| 亚洲天堂男人天堂| 日韩在线国产精品| 91在线观看免费高清| 国产精品视频色| 欧美大荫蒂xxx| 深夜精品寂寞黄网站在线观看| 亚洲人成亚洲人成在线观看| 一区二区三区视频免费| 精品久久久久久亚洲精品| 国产欧美日韩91| 清纯唯美日韩制服另类| 国产精品久久久久久亚洲影视| 国内精品小视频| www日韩欧美| 亚洲精品视频免费| 日韩的一区二区| 国外视频精品毛片| 亚洲国产日韩欧美在线图片| 欧美日韩爱爱视频| 91精品国产综合久久久久久蜜臀| 中文字幕日韩综合av| 国产亚洲欧美另类中文| 中文字幕在线精品| 久久人体大胆视频| 亚洲图片欧美日产| 超碰97人人做人人爱少妇| 国产成人久久久精品一区| 97精品国产97久久久久久| 日本成人精品在线| 在线观看日韩专区| 国产一区二区在线免费| 亚洲国产精品va在看黑人| 亚洲国产又黄又爽女人高潮的| 热久久99这里有精品| 久久理论片午夜琪琪电影网| 欧美日韩福利视频| 亚洲高清久久网| 欧美孕妇毛茸茸xxxx| 成人欧美一区二区三区黑人孕妇| 欧美精品激情在线| 亚洲国产天堂网精品网站| 日韩精品视频中文在线观看| 亚洲性日韩精品一区二区| 国产精品美腿一区在线看| 91探花福利精品国产自产在线| 中文字幕综合在线| 91精品久久久久久久久| 综合av色偷偷网| 亚洲字幕一区二区| 久久精品国产欧美激情| 欧美亚洲国产精品| 亚洲男人天堂网| 国模私拍视频一区| 国产欧美日韩综合精品| 国产精品aaa| 日韩在线视频免费观看高清中文| 亚洲图片在区色| 色琪琪综合男人的天堂aⅴ视频| 日韩免费中文字幕| 亚洲欧美制服第一页| 亚洲综合在线中文字幕| 日韩欧美国产网站| 日本一区二三区好的精华液| 日韩av大片在线| 成人性生交大片免费观看嘿嘿视频| 91精品中文在线| 97热在线精品视频在线观看| 最新91在线视频| 国产欧美 在线欧美|