溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么在JavaScript中使用正則表達(dá)式實(shí)現(xiàn)一個(gè)語(yǔ)法高亮功能

發(fā)布時(shí)間:2021-02-24 16:08:15 來源:億速云 閱讀:233 作者:戴恩恩 欄目:互聯(lián)網(wǎng)科技

本文章向大家介紹怎么在JavaScript中使用正則表達(dá)式實(shí)現(xiàn)一個(gè)語(yǔ)法高亮功能的基本知識(shí)點(diǎn)總結(jié)和需要注意事項(xiàng),具有一定的參考價(jià)值,需要的朋友可以參考一下。

Java的特點(diǎn)有哪些

Java的特點(diǎn)有哪些 1.Java語(yǔ)言作為靜態(tài)面向?qū)ο缶幊陶Z(yǔ)言的代表,實(shí)現(xiàn)了面向?qū)ο罄碚?,允許程序員以優(yōu)雅的思維方式進(jìn)行復(fù)雜的編程。 2.Java具有簡(jiǎn)單性、面向?qū)ο蟆⒎植际?、安全性、平臺(tái)獨(dú)立與可移植性、動(dòng)態(tài)性等特點(diǎn)。 3.使用Java可以編寫桌面應(yīng)用程序、Web應(yīng)用程序、分布式系統(tǒng)和嵌入式系統(tǒng)應(yīng)用程序等。

代碼如下:


(/^\s+|\s+$/) // 匹配首尾空格
(/(["'])(?:\\.|[^\\\n])*?\1/) // 匹配字符串
(/\/(?!\*|span).+\/(?!span)[gim]*/) // 匹配正則 span 是他上次處理加上的,我覺得這里不應(yīng)該出現(xiàn)
(/(\/\/.*|\/\*[\S\s]+?\*\/)/) // 匹配注釋
(/(\*\s*)(@\w+)(?=\s*)/) // 匹配 注釋中的標(biāo)記
(/\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/) // 匹配關(guān)鍵詞

小胡子哥可能是不想重復(fù)造輪子,只是想弄清楚如何造這樣的輪子而已,所以他寫這個(gè)東西點(diǎn)到即止,沒有深入詳細(xì)的處理,做的比較粗糙。
當(dāng)然我也不是說他什么,只是簡(jiǎn)單評(píng)論一下而已,畢竟優(yōu)秀的語(yǔ)法高亮插件多的是,沒必要自己重復(fù)造,學(xué)習(xí)下原理即可。

我們?cè)賮矸治鱿?次碳酸鈷 這篇 《如何實(shí)現(xiàn)正則表達(dá)式的JavaScript的代碼高亮》
其實(shí)這篇已經(jīng)分析的非常詳細(xì)了,我只能簡(jiǎn)單補(bǔ)充說明下。
次碳酸鈷 思維一向比較嚴(yán)謹(jǐn),這篇文章之前我看了一個(gè)多小時(shí),只能看個(gè)大概,這次重新分析了一遍,然后自己實(shí)現(xiàn)了一遍,竟然也花去我半天時(shí)間,
不過非常值得,真心學(xué)到了很多。

先來看一下大體的邏輯吧。

復(fù)制代碼 代碼如下:


(\/\/.*|\/\*[\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 // 匹配關(guān)鍵詞
\b(Object|Array|String|Number|Boolean|Function|RegExp|Date|Math|window|document|navigator|location)\b // 匹配內(nèi)置對(duì)象
\b(true|false)\b // 匹配布爾值
\b(null|undefined|NaN)\b // 匹配各種空值, 我覺得這個(gè)和布爾值一組比較合適。
(?:[^\W\d]|\$)[\$\w]* // 匹配普通的變量名
(0[xX][0-9a-fA-F]+|\d+(?:\.\d+)?(?:[eE]\d+)?) // 匹配數(shù)字 (前者不占用,這里就會(huì)有問題)
(?:[^\)\]\}]|^)(\/(?!\*)(?:\\.|[^\\\/\n])+?\/[gim]*) // 匹配正則
[\S\s] // 其他不能匹配的任意值

原文對(duì)最后一個(gè) [\S\s] 的描述:我們必須匹配到每一個(gè)字符。因?yàn)樗鼈兌夹枰鲆淮蜨TML轉(zhuǎn)義。
然后下面有詳細(xì)的代碼。

這是一篇非常不錯(cuò)的文章,我前前后后至少看了不下10次了,前兩天才差不多完全明白。

不過這個(gè)代碼還有一些小小的瑕疵,比如字符串不能匹配折行那種,字符串匹配優(yōu)化。

還有數(shù)字匹配不夠全面只能匹配 0xff, 12.34, 1e3 這幾類,如 .123 12.3e+3 等格式都無法匹配到。
還有關(guān)鍵詞順序我覺得可以稍微優(yōu)化下。
因?yàn)?傳統(tǒng)型NFA 引擎的只是從左往右匹配,匹配到了就停止下一個(gè)分支的操作。
所以把最常出現(xiàn)的關(guān)鍵詞放前面,可以提升一部分性能。
最后,最好是 new RegExp 這樣對(duì)于代碼量大的代碼性能上會(huì)有所提升。

下面就給出我的正則和簡(jiǎn)單的demo吧。(其實(shí)只是對(duì) 次碳酸鈷 源碼的優(yōu)化而已。。)
先來看正則部分:

復(fù)制代碼 代碼如下:


(\/\/.*|\/\*[\s\S]*?\*\/) // 匹配注釋 沒改
("(?:[^"\\]|\\[\s\S])*"|'(?:[^'\\]|\\[\s\S])*') // 匹配注釋 優(yōu)化過
\b(true|false|null|undefined|NaN)\b // 匹配 布爾和空值,這幾個(gè)比較常用,分組提前
\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 // 匹配關(guān)鍵詞,關(guān)鍵詞順序改了下
\b(document|Date|Math|window|Object|location|navigator|Array|String|Number|Boolean|Function|RegExp)\b //內(nèi)置對(duì)象,單詞順序改了下
(?:[^\W\d]|\$)[\$\w]* // 匹配普通的變量名 沒改
(0[xX][0-9a-fA-F]+|\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|\.\d+(?:[eE][+-]?\d+)?) // 匹配數(shù)字,修復(fù)了匹配
(?:^|[^\)\]\}])(\/(?!\*)(?:\\.|[^\\\/\n])+?\/[gim]*) // 匹配正則,這個(gè)最復(fù)雜,情況很多,我暫時(shí)沒實(shí)力修改
[\s\S] // 匹配其他

合并了布爾和空值一個(gè)分組,然后優(yōu)化了正則分組,所以比他減少了2個(gè)分組。
他 2,3 是字符串分組,因?yàn)?(["']) 捕獲了前面的引號(hào),而我的正則沒這么做。
這個(gè) (true|false|null|undefined|NaN) 如果你不喜歡放在一個(gè)分組了,分開也行、
是不是同一個(gè)分組,只是為了區(qū)分著色而已。
sublime text 下 true|false|null|undefined|NaN 都是一個(gè)顏色,而 notepad++ 則只著色了 true|false ,我只想說 呵呵。

好了,差不多該給例子了。
我相信,不少人在看到這之前已經(jīng)關(guān)掉了,或者只是拉了下滾動(dòng)條然后關(guān)掉了。
不過我寫這個(gè)就是為了給這些認(rèn)真看下來的朋友,只要有一個(gè)人看,我覺得就不會(huì)白寫了。
例子:

復(fù)制代碼 代碼如下:


// 單行注釋
/**
 * 多行注釋
 * @date 2014-05-12 22:24:37
 * @name 測(cè)試一下
 */
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]*?\\*\\/)|("(?:[^"\\\\]|\\\\[\\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: //關(guān)鍵詞 kwd
                            return '<span class="kwd">' + s + '</span>';
                        case 5: //內(nèi)置對(duì)象 obj
                            return '<span class="obj">' + s + '</span>';
                        case 6: //數(shù)字 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>') // 匹配注釋中的標(biāo)記
                   .replace(/(\w+)(\s*\(|(?: )*\()|(\w+)(\s*=\s*function|(?: )*=(?: )*function)/g, '<span class="func">$1</span>$2') // 匹配函數(shù)
        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);

你們可以用下面的代碼進(jìn)行測(cè)試。

代碼:

復(fù)制代碼 代碼如下:


<!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;} /* 注釋標(biāo)記 */
    .str {color:#808080;} /* 字符串 */
    .val {color:#000080;} /* true|false|null|undefined|NaN */
    .kwd {color:#000080;font:bold 12px 'comic sans ms', sans-serif;} /* 關(guān)鍵詞 */
    .obj {color:#000080;} /* 內(nèi)置對(duì)象 */
    .num {color:#FF0000;} /* 數(shù)字 */
    .reg {color:#8000FF;} /* 正則 */
    .func {color:#A355B9;} /* 函數(shù) */
    </style>
</head>
<body>

<code id="regdemon">
// 單行注釋
/**
 * 多行注釋
 * @date 2014-05-12 22:24:37
 * @name 測(cè)試一下
 */
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]*?\\*\\/)|("(?:[^"\\\\]|\\\\[\\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: //關(guān)鍵詞 kwd
                            return '<span class="kwd">' + s + '</span>';
                        case 5: //內(nèi)置對(duì)象 obj
                            return '<span class="obj">' + s + '</span>';
                        case 6: //數(shù)字 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*|(?:&nbsp;)*\*(?:&nbsp;)*)(@\w+)\b/g, '&nbsp;*&nbsp;<span class="comkey">$1</span>') // 匹配注釋中的標(biāo)記
                   .replace(/(\w+)(\s*\(|(?:&nbsp;)*\()|(\w+)(\s*=\s*function|(?:&nbsp;)*=(?:&nbsp;)*function)/g, '<span class="func">$1</span>$2') // 匹配函數(shù)
        return code;
    }


    function htmlEncode(str) {
        var i, s = {
                //"&amp;": /&/g,
                "&quot;": /"/g,
                "&#039;": /'/g,
                "&lt;": /</g,
                "&gt;": />/g,
                "<br>": /\n/g,
                "&nbsp;": / /g,
                "&nbsp;&nbsp;": /\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]*?\\*\\/)|("(?:[^"\\\\]|\\\\[\\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: //關(guān)鍵詞 kwd
                            return '<span class="kwd">' + s + '</span>';
                        case 5: //內(nèi)置對(duì)象 obj
                            return '<span class="obj">' + s + '</span>';
                        case 6: //數(shù)字 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*|(?:&nbsp;)*\*(?:&nbsp;)*)(@\w+)\b/g, '&nbsp;*&nbsp;<span class="comkey">$1</span>') // 匹配注釋中的標(biāo)記
                   .replace(/(\w+)(\s*\(|(?:&nbsp;)*\()|(\w+)(\s*=\s*function|(?:&nbsp;)*=(?:&nbsp;)*function)/g, '<span class="func">$1</span>$2') // 匹配函數(shù)
        return code;
    }


    function htmlEncode(str) {
        var i, s = {
                //"&amp;": /&/g,
                "&quot;": /"/g,
                "&#039;": /'/g,
                "&lt;": /</g,
                "&gt;": />/g,
                "<br>": /\n/g,
                "&nbsp;": / /g,
                "&nbsp;&nbsp;": /\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>

以上就是小編為大家?guī)淼脑趺丛贘avaScript中使用正則表達(dá)式實(shí)現(xiàn)一個(gè)語(yǔ)法高亮功能的全部?jī)?nèi)容了,希望大家多多支持億速云!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI