preg_replace_callback('#<(code|pre)([^>]*)>(((?!</?\1).)*|(?R))*</\1>#si', 'self::replaceit', $text);
?
我正在尝试在代码/预标记之间替换文本,它可以实现我想要的,但有时会破坏页面.
我用几个文本样本测试了它,其中一些包含许多& <等字符使浏览器停止显示带有"远程服务器关闭的连接"消息的页面
我想帮忙.我以前见过这个问题!
你的正则表达式看起来逻辑上是A-Ok,但是当应用于大型主题字符串时,很可能导致大量的递归回溯,这导致PCRE引擎中的堆栈溢出.这种溢出会导致分段错误和PCRE可执行文件(Apache或PHP)崩溃,而不会发出警告.(症状是"远程服务器关闭连接"消息.)这种未处理的崩溃是由于PHP选择pcre.recursion_limit参数的默认设置(默认为100,000,这太高).首先让我们看看这是否是问题的一部分.
将以下代码添加到脚本中:
// Place this at the top of the script
ini_set("pcre.recursion_limit", "524"); // 256KB stack. Win32 Apache
$re = '#<(code|pre)([^>]*)>(((?!</?\1).)*|(?R))*</\1>#si';
$text = preg_replace_callback($re, 'self::replaceit', $text);
// Check the return value for NULL which indicates a PCRE error.
if ($text === null) exit("PCRE Error! Subject too large or complex.");
Run Code Online (Sandbox Code Playgroud)
有了这个,你就不应再得到"连接关闭"消息,而是PCRE错误退出消息.请注意,上面的524设置适用于Win32 Apache httpd.exe(堆栈为256KB).如果您在*nix服务器上运行,则可以将此值提高到16777.这些数字背后的原因是该recursion _limit值应设置为可执行堆栈大小除以500.WIn32可执行文件通常具有256KB堆栈和*nix可执行文件通常使用8MB堆栈构建.Philip Hazel(优秀的 PCRE引擎的作者)已经详细解决了这个问题.请参阅:pcrestack手册页
一旦你完成了这个,请回报,我将帮助完成下一阶段......
(请注意,这不是(?R)导致问题的表达.稍后.)
通过实施Jeffrey Friedl的"Unrolling-the-Loop"效率技术,可以显着改善正则表达式(关于解决这个问题和提高速度).这将大大减少必要的回溯次数,并可能解决您的问题.这是你的正则表达式的改进(并且完全评论)版本.
$re = '% # Match an outermost PRE or CODE element.
( # $1: PRE/CODE element open tag
<(code|pre) # $2: Open tag name
[^>]*+> # Remainder of opening tag.
) # End $1: PRE/CODE element open tag.
( # $3: PRE/CODE element contents.
(?: # Group for contents alternatives
(?R) # Either a nested PRE or CODE element
| # Or non- <CODE, </CODE, <PRE or </PRE stuff.
[^<]*+ # Begin: {normal* (special normal*)*} construct
(?: # See: "Mastering Regular Expressions".
< # {special} Match a <, but only if it is
(?!/?\2) # not the start of a nested or closing tag.
[^<]*+ # match more {normal*}
)*+ # Finish "Unrolling the loop"
)*+ # Zero or more contents alternatives.
) # End $3: PRE/CODE element contents.
(</\2>) # $4: PRE/CODE element close tag
%ix';
Run Code Online (Sandbox Code Playgroud)
但是,这个正则表达式的不同之处在于它使用了四个捕获组:$1包含整个元素的开始标记,$2包含元素标记名称(用作后向引用),$3包含元素内容,并$4包含元素结束标记.
| 归档时间: |
|
| 查看次数: |
656 次 |
| 最近记录: |