总的来说,就是使用正则表达式时,因为其性能是不稳定的,当使用不恰当时,容易引发性能问题。
因为正则表达式会有回溯问题,当匹配的是一串很长的字符串时,如果发生回溯,其计算量就将会是非常的巨大,这就是性能差的主要原因。
什么是回溯呢,就比如匹配字符串“abbc”,正则表达式为/ab{1,3}c/,因为默认是贪婪模式,
所以会尽量匹配多一点内容,也就是想尽量匹配多个b,于是步骤就是如下:
1. a -> a
2. ab -> ab
3. abb -> abb
4. abbb -> abbc
5. abb -> abb
6. abbc -> abbc
如上,第4步因为想要尽可能的匹配多一点内容,所以想要匹配3个b,但是没匹配上,匹配到了c,
于是就回溯,然后匹配下一个正则表达式,也就是c,然后c与c匹配,成功返回。
这就是正则表达式的回溯问题,当需要匹配的是一个超长字符串,并且发生了回溯问题,那其计算量能够想象有多大了吧。
解决回溯问题:
由于是因为贪婪模式导致的,那只要把贪婪模式改为懒惰模式即可,只要后面加个“?”就行,改为/ab{1,3}?c/
但是懒惰模式也无法完全回溯问题,比如:字符串“abbc”,正则表达式/ab{1,3}?c/,则步骤如下:
1. a -> a
2. ab -> ab
3. abc -> abb
4. ab -> ab
5. abb -> abb
6. abbc -> abbc
如上,第3步因为想要尽可能少匹配一点内容,于是就只匹配一个b,但没匹配上,于是就回溯,
与贪婪模式相反,贪婪模式是字符串回溯,而懒惰模式是正则表达式回溯。
使用独占模式,只要后面加个“+”就行,改为/ab{1,3}+c/
因为独占模式是只要不匹配就结束,不会进行回溯,但是也不能完全解决回溯问题,因为其也是会尽可能的匹配多一点内容,所以也会导致回溯问题。
总的来说,懒惰模式和独占模式都是只能减少回溯问题,但是不能完全避免回溯问题。
可优化方案:
1. 少用贪婪模式,多用独占模式;
2. 减少分支选择,比如(X|Y|Z)这种分支选择,如要只用分支,可以将常用的选项放在前面,可以提取公共因子,比如(aabb|aacc|aadd)可以换成aa(bb|cc|dd),可以用三次匹配来代替(X|Y|Z);
3. 减少捕获嵌套,就是一个()代表一个捕获组,比如/a(bc)de(fgh)ijk(lmn)/,然后\1代表(bc),\2代表(fgh),\3代表(lmn),
非捕获组就是(?:X),比如/a(?:bc)de(fgh)ijk(?:lmn)/,则\1代表(fgh),或者直接不用括号/abcde(fgh)ijklmn/;
4. 能不用正则表达式就不用正则表达式。
正则表达式的回溯
最新推荐文章于 2023-08-08 20:02:23 发布