正则表达式学习——(2)正则回溯


参考文章:

https://www.zhihu.com/question/48219401/answer/1476436385

https://www.jianshu.com/p/48dc319f68f3

https://www.cnblogs.com/chanshuyi/p/9197164.html

https://www.cnblogs.com/study-everyday/p/7426862.html

一、正则回溯是什么

首先,回溯是什么?

​ 回溯法是一种通用的计算机算法,用于查找某些计算问题的所有(或某些)解决方案,特别是约束满足问题,逐步构建候选解决方案,并在确定候选不可能时立即放弃候选(“回溯”)完成有效的解决方案。

​ 回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:
​ 1.找到一个可能存在的正确的答案;

​ 2.在尝试了所有可能的分步方法后宣告该问题没有答案

这里借用参考文章里的例子,这里表现了/ab{1,3}bc/g这个正则表达式是怎么回溯地匹配abbc的:

img

  1. 正则引擎先匹配 a。
  2. 正则引擎尽可能多地(贪婪)匹配 b{1,3}中的 b。
  3. 正则引擎去匹配 b,发现没 b 了,糟糕!赶紧回溯!
  4. 返回 b{1,3}这一步,不能这么贪婪,少匹配个 b。
  5. 正则引擎去匹配 b。
  6. 正则引擎去匹配 c,完成匹配。

正则表达式使用的引擎实现是 NFA(这个我还没怎么看懂,先码一个) ,像 javaScript、java、php、python、c#等语言的正则引擎都是 NFA 型,这种正则表达式引擎在进行字符匹配时会发生回溯(backtracking)。而回溯的时间长短取决于回溯的次数和复杂度。在最坏的情况下,回溯法会导致一次复杂度为指数时间的计算,这就会导致 CPU 使用率高,响应缓慢,也就是回溯陷阱(Catastrophic Backtracking)

二、怎么避免回溯陷阱?

正则表达式中有这么三种模式:贪婪模式、懒惰模式、独占模式。

  • 单独使用 + ? * {min,max} 这几个特殊字符,那么就是贪婪模式。

  • 如果在他们之后加多一个 ? 符号,那么原先的贪婪模式就会变成懒惰模式,即尽可能少地匹配。不过以懒惰匹配的方式去匹配文本,也不能避免回溯。例如正则/ab{1,3}?c/g去匹配abbc,不会发生回溯的正则,因为使用了惰性量词进行懒惰匹配后,反而产生了回溯惹。

  • 如果在以上四种表达式后加上一个加号+,则会开启独占模式。同贪婪模式一样,独占模式一样会匹配最长。不过在独占模式下,正则表达式尽可能长地去匹配字符串,一旦匹配不成功就会结束匹配而不会回溯。例如正则/ab{1,3}+c/g去匹配abbc,在正则中的b和文本中的c进行匹配时,无法匹配也不进行回溯,这时候整个文本就无法和正则表达式发生匹配。

bc`,在正则中的b和文本中的c进行匹配时,无法匹配也不进行回溯,这时候整个文本就无法和正则表达式发生匹配。

如果一个过长字符串进行匹配,一旦发生回溯,计算量将是巨大的。我看网上参考文章因为正则NFA回溯这个特性,博主在测试环境没有发现问题,但是一到线上的时候就发生了 CPU 100% 的问题。然后采用了独占模式,CPU占用过高的问题才得到了解决。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值