性能提升:正则表达式的优化

664 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天。

我相信对大多数程序员来说,正则表达式都是一个难点,更别说优化了,不过我们还是要硬着头皮看看该怎么优化,没准领导会涨你工资哦~

匹配同一个文本,不同的正则表达式运行的速度可能会很不一样哦,正则表达式运行的效率受很多不同因素的影响:

  • 部分匹配比完全不匹配所用的时间要长
  • 不同浏览器对正则表达式引擎有不同程度的内部优化

正则表达式的工作原理

正则表达式处理的基本步骤:

(1)编译

(2)设置起始位置

(3)匹配每个正则表达式字元

(4)匹配成功或失败

回溯

回溯是匹配过程的基础组成部分,是正则表达式如此强大且富有表达力的根源,但是回溯会产生昂贵的计算能耗。

百度百科定义:

回溯是计算机算法,回溯法也称试探法,它的基本思想是:从问题的某一种状态(初始状态)出发,搜索从这种状态出发所能达到的所有“状态”,当一条路走到“尽头”的时候(不能再前进),再后退一步或若干步,从另一种可能“状态”出发,继续搜索,直到所有的“路径”(状态)都试探过。这种不断“前进”、不断“回溯”寻找解的方法,就称作“回溯法”。

正则表达式也是这种匹配过程,从左到右逐个测试表达式的组成部分,看是否能匹配到目标字符串。在遇到量词(*, +?等)时决定何时尝试匹配更多字符,遇到分支时(|)必须从可选项中的下一个字符,再重复此过程。

回溯失控

当正则表达式导致浏览器假死,很可能是因为回溯失控。

解决方案:具体化

解决方案是尽可能具体化分隔符之间的字符串匹配模式,比如. * ?,它用来匹配一个由双引号包围的字符串,这样就可以去除回溯时可能发生的几种情况,比如尝试用点好匹配引号或扩展搜索超出预期范围。

更多提高表达式效率的方法

关注如何让匹配更快失败

如果你使用正则表达式来匹配一个大字符串的一小部分,该正则表达式匹配失败的位置比匹配成功的位置要多的多

正则表达式以简单、必需的字元开始

最理想的情况是,一个正则表达式的其实标记应尽可能快速的测试并排除明显不匹配的位置。

使用量词模式,使他们后面的字元互斥

当字符与字元相邻或子表达式能重叠匹配时,正则表达式尝试拆解文本的路径数量将增加。为避免这种情况,要尽量具体化匹配模式,比如当你想表达“[^"\s\n]”时不要使用“。?”(它依赖回溯)。

使用非捕获组

只捕获感兴趣的文本减少后期处理

将浮在的正则表达式拆分为简单的片段(化繁为简)