js 玩转正则表达式之语法高亮

学了几天正则,差不多该总结整理写成果了,之前就想写语法高亮匹配来着,不过水平不够,看着例子都不理解。

那么我们来分析下两位大神 次碳酸钴 和 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]*?\*\/) // 匹配注释 没改
("(?:[^"\\]|\\[\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] // 匹配其他

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wfywws.html