.*?开头的正则为什么容易造成死循环?

解决方案 »

  1.   

    .*?<value><源代码比较长,当源代码中匹配不到<value><就造成了死循环。
    个人认为.*?<value><和<value><效果应该是一样的哈,但是为什么前者会     
      

  2.   


    不是死循环,只是循环的次数太多,占用的时间过长罢了
    在匹配成功的情况下,一般不会出现这种情况,在匹配失败的情况下,源字符串的长度越长,循环的次数就越多,当源字符串达到一定长度的时候,会出现假死现象这个跟NFA引擎的匹配原理相关,要完全说清楚,不是一句话两句话的事,简单的说一下吧源字符串以“abcde”为例,说明一下
    .*?<value> 小数点匹配除\n外的任意字符,而*?是忽略优先的(或者叫非贪婪模式),.*?可以看作是一组,后面接字符“<”,再后面接字符“v”匹配过程:
    首先从字符串开始的位置匹配,“.*?”取得控制权,但是由于它是忽略优先的,所以什么都不匹配,把控制权关给“<”,如果匹成功,控制权关给“v”,如果匹配不成功,那么就会发生回溯,控制权交给“.*?”,这里由于第一个字符是“a”,所以“<”匹配不成功,这时由“.*?”来匹配“a”,然后继续尝试向后匹配
    “.*?”取得控制权,但是由于它是忽略优先的,所以什么都不匹配,把控制权关给“<”,由于第二个字符是“b”,所以“<”匹配不成功,控制权重新关给“.*?”,匹配成功,这时由“.*?”来匹配“a”,然后继续尝试向后匹配

    重复以上过程,一直到由“.*?”匹配了“abcde”,这时控制权交给“<”,到了字符串结束位置,匹配不成功,这时候会报整个表达式匹配不成功正则引擎向前传动,由“ab”之间的位置开始尝试匹配,再重复以上过程,直到匹配失败正则引擎继续传动,一直到字符串的结束位置,这时会报告整个匹配过程失败,匹配完成所以源字符串越长,匹配过程中控制权的交替就越多,而这种操作是很耗时的,甚至可以相当于无限循环那么如何解决这个问题
    如果是从字符串开始位置匹配的,那么在前面加上“^”,即“^.*?<value>”,一般稍微做了一点优化的正则引擎,只要第一次从开始位置匹配失败了,就不会再尝试第二个位置开始的匹配,直接报告整个匹配过程失败,那么匹配性能的提高就是指数级的但这还不够,如果源字符串很长,那么这个匹配时间仍然会很长,所以通常情况下,需要采用匹配优先(或者叫贪婪模式)的方式,可以用排除型字符组或者否定正向环视来实现,因为这里要排除的是一个子字符串,所以用否定型正向环视^((?!<value>).)*<value>
    这样的优化会将匹配效率再提升一个数量级当然,这并不是最终的优化形态,还可以采用固化分组进行优化
    ^(?>(?:(?!<value>).)*)<value>涉及到长字符串匹配或对性能要求较高时,不要使用.*?这种忽略优先(非贪婪模式)的写法