js 正则学习小记之匹配字符串优化篇

昨天在《js 正则学习小记之匹配字符串》谈到 /"(?:\\.|[^"])*"/
是个不错的表达式,因为可以满足我们的要求,所以这个表达式可用,但不一定是最好的。
从性能上来说,他非常糟糕,为什么这么说呢,因为 传统型NFA引擎
遇到分支是从左往右匹配的,
所以它会用 \\.
去匹配每一个字符,发现不对后才用 [^"]
去匹配。
比如这样一个字符串: "123456\‘78\"90"
共 16
个字符,除了第一个 " 直接匹配成功,还剩余 15 个,只有 2
个转义(4 个字符),所以 \\.
会失败 10 次,只有 2
次成功。
这 10 次匹配失败,需要回溯后用 [^"]
才能匹配成功,当然最后一个 " 会直接匹配成功。

很明显,正常的字符串不可能全是转义,正常的字符串才是主流,当然不排除有人故意全转义的情况。
所以这个正则需要10次回溯后才能匹配完成,如果字符串增长到
1K 1M
肿么破呢?
所以我们要修改下这个正则,前后换下位置么?
难道是 /"(?:[^"]|\\.)*"/
? 呵呵,好像不太对,这样的话转义就不能被匹配了。

所以还要修改下 /"(?:[^"\\]|\\.)*"/
这样就OK了,遇到 \ 转义就会用 \\.
去尝试匹配。

可是还是有问题,因为我们在 [^"\\]
过滤掉了 \n 所以没法匹配多行字符的情况。

js 中 字符串用 \ 折行是允许的,但是修改后的 正则
没法匹配这样的字符串了,所以我们还得继续修复。
因为 .
没法匹配换行,所以我们要用其他方式表达。
.
是用于匹配除换行符之外的所有字符,难道我们要 [.\n]
来表示么?
这样是不对的,因为 []
字符集中的 . 不再表示除换行符之外的所有字符,而是字符 .
也就是他本身一个字符而已。
那怎么办呢?
其实换个思路,
\d
表示 0-9
\D
表示 [^0-9]
那么
[\d\D]
就表示所有了,不是么。(新人朋友不知道能不能消化这个知识点。)
同理 [\s\S]
[\w\W] 同样可以。
所以 /"(?:[^"\\]|\\[\d\D])*"/
这样就满足我们的要求了。

效果不错。
回头过来分分析下他现在的性能吧。
还是这个字符串: "123456\‘78\"90"
, 正则 /"(?:[^"\\]|\\[\d\D])*"/

共 16 个字符,除了第一个
" 直接匹配成功,还剩余 15 个,有 2 个转义(4 个字符),[^"\\]
能匹配成功 10 个字符,只有 2
次失败。
为什么不是 4 次失败呢,明明有4个字符啊。\\ 虽然是2个字符,但是读到第一个
\ 就匹配失败,然后用 \\[\d\D]
匹配成功,
占用掉了两个字符 \\ 下次用下一个o开始匹配,所以只有2次回溯。
只有 2
次需要回溯,然后用 \\[\d\D]
匹配成功。当然最后一个 " 还是会直接匹配成功。
所以从
10 次回溯,减少到了 2
次,虽然正则比昨天臃肿了很多,但至少性能提升了不止一个等级。

OK,今天的分享完毕,明天见。

时间: 2024-09-29 23:44:37

js 正则学习小记之匹配字符串优化篇的相关文章

js 正则学习小记之匹配字符串

原文:js 正则学习小记之匹配字符串 今天看了第5章几个例子,有点收获,记录下来当作回顾也当作分享. 关于匹配字符串问题,有很多种类型,今天讨论 js 代码里的字符串匹配.(因为我想学完之后写个语法高亮练手,所以用js代码当作例子) var str1 = "我是字符串1哦,快把我取走", str2 = "我是字符串2哦,快把我取走"; 比如这样一个字符串,匹配起来很简单 /"[^"]*"/g 即可. PS: 白色截图是 chrome 3

js 正则学习小记之NFA引擎

之前一直认为自己正则还不错,在看 次碳酸钴,Barret Lee 等大神都把正则玩的出神入化后发现我只是个战五渣.  求抱大腿,求大神调教. 之前大致有个印象,正则有很多种引擎,但我根本不知道有哪些引擎. 今天在读<精通正则表达式>才发现有Traditional NFA,POSIX NFA 和 DFA (具体自己百度下吧).可用了这么久的正则,还不知道 js 属于哪一种呢.在<精通正则表达式>里有个简单是方法检测属于哪一种. 用 /nfa|nfa not/ 去匹配 "nf

js正则学习

一直对正则很纠结也很畏惧,以前感觉花时间理解一个个奇奇怪怪的符号,还不如直接百度谷歌之. 但知其然不知其所以然也是种痛苦,所以花了两天稍微学了一下,虽然没学很深入彻底,但也比之前进步不少,特此笔记. js正则 g:表示全局,匹配全部i:表示不区分大小写m:表示匹配多行(匹配换行两端的潜在匹配) RegExp实例属性: global:是否设置了g ignoreCase:是否设置了i  lastIndex:表示下一次exec开始搜索下个匹配项的字符位置  multiline:表示是否设置了m  so

js正则学习及一些正则集合

正则中文版详细说明请看中文版w3cschool-----http://www.w3school.com.cn/jsref/jsref_obj_regexp.asp偶还看微软正则表达式语言-快速参考:http://msdn.microsoft.com/zh-cn/library/az24scfc%28v=vs.110%29.aspx var reg=/(123)/;            var str='abc123';            str=str.replace(reg,'***')

JS正则[egExp]小记

new RegExp(pattern,attribute) 参数pattern:字符串,指定了正则表达式的模式和其他正则表达式 参数attribute是一个可选的字符串,包含属性'g','i','m',如果pattern是正则表达式而不是字符串的时候要省略m 返回值 一个新的RegExp对象,具有指定的模式和标志.如果参数pattern是正则表达式而不是字符串,那么RegExp()构造函数将用于指定的RegExp相同模式和标志创建一个新的RegExp对象 如果不用new用算符,而是将RegExp

js 正则练习之语法高亮

原文:js 正则练习之语法高亮 学了几天正则,差不多该总结整理写成果了,之前就想写语法高亮匹配来着,不过水平不够,看着例子都不理解.今天就分析下 次碳酸钴 和 Barret Lee 语法高亮实现. 先说 Barret Lee 的这篇 <玩转正则之highlight高亮>之前看的时候只觉的神奇,特别是下面那个一步一步分开匹配的例子,更是霸气测漏,不过作者也说了,分开只是为了演示方便,可以很直观的看到这一步匹配了什么,不然一步到位匹配完成,你都不知道发生了什么就处理完毕了.来看下他的正则 (/^\

浅谈 js 正则字面量 与 new RegExp 执行效率

前几天谈了正则匹配 js 字符串的问题:<js 正则学习小记之匹配字符串> 和 <js 正则学习小记之匹配字符串优化篇>.里面讲到了优化正则起到提升性能的问题,但是能提升多少呢?于是我去测试了,发现TMD几乎微乎其微,我用1千字符串进行100万次匹配测试,优不优化根本没区别. 这不科学,我白看了这么多天正则,上天这是在玩弄我么. 突然我想到了 compile 方法,然后去测试了下,奇迹出现了,果然优化过的快了不少. 但这是为什么呢?于是我翻阅资料,在 MDN 上找到了 RegExp

js正则实现从一段复杂html代码字符串中匹配并处理特定信息

js正则实现从一段复杂html代码字符串中匹配并处理特定信息 问题: 现在要从一个复杂的html代码字符串(包含各种html标签,数字.中文等信息)中找到某一段特别的信息(被一对“|”包裹着),并对他进行加粗.加下滑线处理. 解决思路: 1.用正则匹配“|”出现的次数,处理刚好出现2次的(html字符串中一般不会含有这个字符) 2.使用正则分组,获取“|”之间的内容,并进行替换(添加样式) 代码: function specialDeal(){ htmlStr = htmlStr.replace

Python 学习第十八天 js 正则及其它前端知识

一,js 正则表达式 test 判断制度串是否符合规定的正则 (1)定义正则表达式匹配规则         js 中定义正则表达式为rep=/\d+/,两个//之间为正则模式 (2)rep.test("assdsda89sdasdas") ,返回true,一般test 方法为只要字符串中的包含正则模式即返回true (3)rep=/^\d+$/完全匹配正则模式    exec 获取匹配的数据 1, (1)rep=/\d+/; (2)str="wangshen_67_houya