昨天在《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,本日的分享完毕,来日诰日见。