首页 > PHP资讯 > HTML5培训技术 > js正则练习之语法高亮

js正则练习之语法高亮

HTML5培训技术
之前看的时候只觉的神奇,特别是下面那个一步一步分开匹配的例子,更是霸气测漏,不过作者也说了,分开只是为了演示方便,可以很直观的看到这一步匹配了什么,不然一步到位匹配完成,你都不知道发生了什么就处理完毕了。
来看下他的正则
 
(/^s+|s+$/) // 匹配首尾空格
(/(["'])(?:\.|[^\n])*?1/) // 匹配字符串
(//(?!*|span).+/(?!span)[gim]*/) // 匹配正则 span 是他上次处理加上的,我觉得这里不应该出现
(/(//.*|/*[Ss]+?*/)/) // 匹配注释
(/(*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的代码高亮》
其实这篇已经分析的非常详细了,我只能简单补充说明下。
次碳酸钴 思维一向比较严谨,这篇文章之前我看了一个多小时,只能看个大概,这次重新分析了一遍,然后自己实现了一遍,竟然也花去我半天时间,
不过非常值得,真心学到了很多。
 
先来看一下大体的逻辑吧。
(//.*|/*[Ss]+?*/) // 匹配注释
((["'])(?:\.|[^\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 // 匹配各种空值, 我觉得这个和布尔值一组比较合适。
(?:[^Wd]|$)[$w]* // 匹配普通的变量名
(0[xX][0-9a-fA-F]+|d+(?:.d+)?(?:[eE]d+)?) // 匹配数字 (前者不占用,这里就会有问题)
(?:[^)]}]|^)(/(?!*)(?:\.|[^\/n])+?/[gim]*) // 匹配正则
[Ss] // 其他不能匹配的任意值
原文对最后一个 [Ss] 的描述:我们必须匹配到每一个字符。因为它们都需要做一次HTML转义。
然后下面有详细的代码。
 
这是一篇非常不错的文章,我前前后后至少看了不下10次了,前两天才差不多完全明白。
不过这个代码还有一些小小的瑕疵,比如字符串不能匹配折行那种,字符串匹配优化,我之前文章大篇幅的讨论了这个问题。
详见:《js 正则学习小记之匹配字符串》 和 《js 正则学习小记之匹配字符串优化篇》
还有数字匹配不够全面只能匹配 0xff, 12.34, 1e3 这几类,如 .123 12.3e+3 等格式都无法匹配到。
还有关键词顺序我觉得可以稍微优化下。
因为 传统型NFA 引擎的只是从左往右匹配,匹配到了就停止下一个分支的操作。
所以把最常出现的关键词放前面,可以提升一部分性能。
最后,最好是 new RegExp 这样对于代码量大的代码性能上会有所提升。
 
下面就给出我的正则和简单的demo吧。(其实只是对 次碳酸钴 Encode(s);
                    switch (i) {
                        case 1: //注释 com
                            return '' + s + '';
                        case 2: //字符串 str
                            return '' + s + '';
                        case 3: //true|false|null|undefined|NaN val
                            return '' + s + '';
                        case 4: //关键词 kwd
                            return '' + s + '';
                        case 5: //内置对象 obj
                            return '' + s + '';
                        case 6: //数字 num
                            return '' + s + '';
                        case 7: //正则 reg
                            return htmlEncode(a[0]).replace(s, '' + s + '');
                    }
                }
            }
            return htmlEncode(a[0]);
        });
        code = code.replace(/(?:s**s*|(?: )**(?: )*)(@w+)b/g, ' * $1') // 匹配注释中的标记
                   .replace(/(w+)(s*(|(?: )*()|(w+)(s*=s*function|(?: )*=(?: )*function)/g, '$1$2') // 匹配函数
        return code;
    }
 
 
    function htmlEncode(str) {
        var i, s = {
                //"&": /&/g,
                """: /"/g,
                "'": /'/g,
                "<": //g,
                "
": /n/g,
                " ": / /g,
                "  ": /t/g
            };
        for (i in s) {
            str = str.replace(s[i], i);
        }
        return str;
    }
 
    window.prettify = prettify;
})(window);
这就是渲染后的代码了,由于代码比较长,复制上来后被博客园格式化后代码格式不对了,所以我直接把渲染后的html直接复制上来了。
 
你们可以用下面的代码进行测试。
 
代码:
 
   
    test
   
 
// 单行注释
/**
 * 多行注释
 * @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]*?\*\/)|("(?:[^"\\]|\\[\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(/rn|[rn]/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 '' + s + '';
                        case 2: //字符串 str
                            return '' + s + '';
                        case 3: //true|false|null|undefined|NaN val
                            return '' + s + '';
                        case 4: //关键词 kwd
                            return '' + s + '';
                        case 5: //内置对象 obj
                            return '' + s + '';
                        case 6: //数字 num
                            return '' + s + '';
                        case 7: //正则 reg
                            return htmlEncode(a[0]).replace(s, '' + s + '');
                    }
                }
            }
            return htmlEncode(a[0]);
        });
        code = code.replace(/(?:s**s*|(?: )**(?: )*)(@w+)b/g, ' * $1') // 匹配注释中的标记
                   .replace(/(w+)(s*(|(?: )*()|(w+)(s*=s*function|(?: )*=(?: )*function)/g, '$1$2') // 匹配函数
        return code;
    }
 
 
    function htmlEncode(str) {
        var i, s = {
                //"&": /&/g,
                """: /"/g,
                "'": /'/g,
                "<": /
                ">": />/g,
                "
": /n/g,
                " ": / /g,
                "  ": /t/g
            };
        for (i in s) {
            str = str.replace(s[i], i);
        }
        return str;
    }
 
    window.prettify = prettify;
})(window);
 
《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(/rn|[rn]/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 '' + s + '';
                        case 2: //字符串 str
                            return '' + s + '';
                        case 3: //true|false|null|undefined|NaN val
                            return '' + s + '';
                        case 4: //关键词 kwd
                            return '' + s + '';
                        case 5: //内置对象 obj
                            return '' + s + '';
                        case 6: //数字 num
                            return '' + s + '';
                        case 7: //正则 reg
                            return htmlEncode(a[0]).replace(s, '' + s + '');
                    }
                }
            }
            return htmlEncode(a[0]);
        });
        code = code.replace(/(?:s**s*|(?: )**(?: )*)(@w+)b/g, ' * $1') // 匹配注释中的标记
                   .replace(/(w+)(s*(|(?: )*()|(w+)(s*=s*function|(?: )*=(?: )*function)/g, '$1$2') // 匹配函数
        return code;
    }
 
 
    function htmlEncode(str) {
        var i, s = {
                //"&": /&/g,
                """: /"/g,
                "'": /'/g,
                "<": /
                ">": />/g,
                "
": /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》
本文由欣才IT学院整理发布,未经许可,禁止转载。