对于如下的正则

/<script>.*?<\/script>/is

当要匹配的字符串长度大于100014的时候, 就不会得出正确结果:

$reg = "/<script>.*?<\/script>/is";
$str = "<script>********</script>"; //长度大于100014
$ret = preg_replace($reg, "", $str); //返回NULL

难道正则对匹配的串有长度限制?

不是, 当然不是, 原因是这样的, 在PHP的pcre扩展中, 提供了俩个设置项.

1. pcre.backtrack_limit //最大回溯数
2. pcre.recursion_limit //最大嵌套数

默认的backtarck_limit是100000(10万).

这个问题, 就和设置项backtrack_limit有关系. 现在要弄清这个问题的原因, 关键就是什么是”回溯”.

这个正则, 使用非贪婪模式, 非贪婪模式匹配原理简单来说是, 在可配也可不配的情况下, 优先不匹配. 记录备选状态, 并将匹配控制交给正则表达式的下一个匹配字符, 当之后的匹配失败的时候, 再溯, 进行匹配.

举个例子:

源字符串: aaab
正则: .*?b

匹配过程开始的时候, “.*?”首先取得匹配控制权, 因为是非贪婪模式, 所以优先不匹配, 将匹配控制交给下一个匹配字符”b”, “b”在源字符串位置1匹配失败(“a”), 于是回溯, 将匹配控制交回给”.*?”, 这个时候, “.*?”匹配一个字符”a”, 并再次将控制权交给”b”, 如此反复, 最终得到匹配结果, 这个过程中一共发生了3次回溯.

现在我们来看看文章开头的例子, 默认的backtrack_limit是100000, 而源字符串的开头是9个字符, 一共是99997个字符.

另外, 因为match函数自身的逻辑, 在文章开头的例子下, 会导致回溯计数增3(有兴趣的可以参看pcrelib/pcre_exec.c中match函数逻辑部分), 所以在匹配到"“之前, pcre中的回溯计数刚好是100000,于是就正常匹配, 退出.

而, 只要在增加一个字符, 就会导致回溯计数大于100000, 从而导致匹配失败退出.

在PHP 5.2以后, 提供了:

int preg_last_error ( void )
Returns the error code of the last PCRE regex execution.

我们应该经常检查这个函数的返回值, 当不为零的时候说明上一个正则函数出错, 特别的对于文章的例子, 出错返回(PREG_BACKTRACK_LIMIT_ERROR)

最后, 在顺便说一句, 非贪婪模式导致太多回溯, 必然会有一些性能问题, 适当的该写下正则, 是可以避免这个问题的. 比如将文章开头例子中的正则修改为:

/<script>[^<]*<\/script>/is

就不会导致这么多的回溯了~

而recursion_limit限制了最大的正则嵌套层数, 如果这个值, 设置的太大, 可能会造成耗尽栈空间爆栈. 默认的100000似乎有点太大了…

就比如对于一个长度为10000的字符串, 如下这个看似”简”的单正则:

//默认recursion_limit为100000
$reg = /(.+?)+/is;
$str = str_pad("laruence", 10000, "a"); //长度为1万
$ret = preg_repalce($reg, "", $str);

会导致core, 这是因为嵌套太多, 导致爆栈.

当然, 你可以通过修改栈的大小来暂时的解决这个问题, 比如修改栈空间为20M以后, 上面的代码就能正常运行, 但这肯定不是最完美的解法. 根本之道, 还是优化正则.

最后: 正则虽易, 用好却难.. 尤其在做大数据量的文本处理的时候, 如果正则设计不慎, 很容易导致深度嵌套, 另外考虑到性能, 还是建议能用字符串处理尽量使用字符串处理代替.

转自:http://www.laruence.com/2010/06/08/1579.html

												

深悉正则(pcre)最大回溯/递归限制的更多相关文章

  1. 2553 ACM N皇后 回溯递归

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2553 中文题目,题意很简单. 思路:听说这是学习递归的经典题目,就来试试,发现自己一点想法都没有,一遇到递 ...

  2. #C++初学记录(N皇后#回溯递归)

    <font size=5 face"微软雅黑">N皇后Problem Description <font size=4 face"微软雅黑"& ...

  3. 再谈循环&迭代&回溯&递归&递推这些基本概念

    循环:不断重复进行某一运算.操作. 迭代:不断对前一旧值运算得到新值直到达到精度.一般用于得到近似目标值,反复循环同一运算式(函数),并且总是把前一 次运算结果反代会运算式进行下一次运算 递推:从初值 ...

  4. 11.字符串{a,b}的幂集[回溯递归]

    我一直在想着这个事,早晨起来五六点,躺在床上冥想.突然悟解了,真如某些书上写的,大道不过三言两语,说破一文不值.还是按照老方法,把问题最大程度的精简,现在求集合A={a,b}的幂集,只有两个元素,应该 ...

  5. Chinese Mahjong UVA - 11210 (暴力+回溯递归)

    思路:得到输入得到mj[]的各个牌的数量,还差最后一张牌.直接暴力枚举34张牌就可以了. 当假设得到最后一张牌,则得到了的牌看看是不是可以胡,如果可以胡的话,就假设正确.否者假设下一张牌. 关键还是如 ...

  6. 单词拼接(dfs/回溯/递归)

    单词拼接传送门 //单词拼接 #include<stdio.h> #include<string.h> #include<algorithm> using name ...

  7. 2019 深信服 下棋(DFS+回溯)

    链接:https://www.nowcoder.com/questionTerminal/a0feb0696e2043a5b3b0779fa861b64a?f=discussion来源:牛客网 8x8 ...

  8. 转:如何调试PHP的Core之获取基本信息

    其实一直想写这个系列, 但是一想到这个话题的宽泛性, 我就有点感觉无法组织. 今天我也不打算全部讲如何调试一个PHP的Core文件, 也不会介绍什么是Coredump, 选择一个相对比较简单的方向来介 ...

  9. php 502 无错误行和报错文件的情况下使用gdb调试方法

    lnmp环境 gdb  /usr/local/php5.2/bin/php-cgi  /tmp/coredump-php-cgi.20503 source /home/tmp/lnmp1.4-full ...

随机推荐

  1. ASP.Net Core开发(踩坑)指南

    ASP.NET与ASP.NET Core很类似,但它们之间存在一些细微区别以及ASP.NET Core中新增特性的使用方法,在此之前也写过一篇简单的对比文章ASP.NET MVC应用迁移到ASP.NE ...

  2. MySQL 关于性能的参数配置梳理

    以下List是我们常见的MySQL参数配置,这个参数对提高实例的性能大有裨益. 其中 建议设置值,仅供参考,需要根据自己的业务场景和硬件资源仔细推敲. 参数 设置说明 建议设置值 lower_case ...

  3. 从0开始的Python学习018更多的Python内容

    特殊的方法 之前学习的都是一些常用的方法,为了使我们的学习更加的完整,我们在这里学习一些特殊的方法. 一般说来,特殊的方法都被用来模仿某个行为.例如,如果你想要为你的类使用x[key]这样的索引操作( ...

  4. PIC单片机基础1

    1.PIC单片机总线结构——哈佛结构:即指令和数据空间是完全分开的,所以与常见的微控制器不同的一点是,程序和数据总线可以采用不同的宽度.以PIC16F684单片机为例,数据总线是8位的,但指令总线位数 ...

  5. python进阶之生成器

    迭代器 什么叫迭代 可以被for循环的就说明他们是可迭代的,比如:字符串,列表,字典,元祖,们都可以for循环获取里面的数据 下面我们看一个代码: number = 12345 for i in nu ...

  6. 解决在使用gensim.models.word2vec.LineSentence加载语料库时报错 UnicodeDecodeError: 'utf-8' codec can't decode byte......的问题

    在window下使用gemsim.models.word2vec.LineSentence加载中文维基百科语料库(已分词)时报如下错误: UnicodeDecodeError: 'utf-8' cod ...

  7. Python--day14(迭代器)

    今日主要内容 1.  带参装饰器 (了了解) 2.  迭代器(*****) 可迭代对象 迭代器对象 for迭代器 枚举对象 1.  带参装饰器 1.  通常,装饰器为被装饰的函数添加新功能,需要外界的 ...

  8. iOS 关于监听手机截图,UIView生成UIImage, UIImage裁剪与压缩的总结

    一.  关于监听手机截图 1. 背景: 发现商品的售价页总是被人转发截图,为了方便用户添加截图分享的小功能 首先要注册用户截屏操作的通知 - (void)viewDidLoad { [super vi ...

  9. protobuf使用详解

    https://blog.csdn.net/skh2015java/article/details/78404235 原文地址:http://blog.csdn.net/lyjshen/article ...

  10. 将root 当成arraylist放入数据sturts2 入门笔记

    刚启动idea 就报出错误 [-- ::,] Artifact -sturts2:war exploded: Error during artifact deployment. See server ...