2

为什么会出现以下段错误,我该如何预防?

<?php

$str = ' <fieldset> <label for="go-to">Go to: </label>  ' 
       . str_repeat(' ', 10000) 
       . '<input type="submit" value="Go" /> </fieldset> </form>';

preg_match_all("@
</?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags
(?:[^<]|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* #allow text and some inline tags
[\?\!\.]+
@ix", $str, $matches);

?>

我相信它会导致......等待它......堆栈溢出。

编辑:

以上是演示问题的模式的简化版本。更完整的版本:

@
</?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags
(?:[^<]|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* # continue, allow text content and some inline tags

# normal sentence ending
[\?\!\.]+ # valid ending characters -- note elipses allowed
(?<!\b[ap]m\.)(?<!\b[ap]\.m\.)(?<!digg this\!)(?<!Stumble This\!) # disallow some  false positives that we don't care about
\s*
(?:&apos;|&\#0*34;|'|&lsquo;)?\s* # closing single quotes, in the unusual case like "he said: 'go away'".
(?:"|&quot;|&\#0*34;|&\#x0*22;|&rdquo;|&\#0*8221;|&\#x0*201D;|''|``|\xe2\x80\x9d|&\#0*148;|&\#x0*94;|\x94|\))?\s* # followed by any kind of close-quote char
(?=\<) # should be followed by a tag.
@ix

目的是找到似乎以有效英文句子结尾结尾的 html 块。我发现这种方法非常擅长区分“内容”文本(如文章正文)和“布局”文本(即,如导航元素)。但是,有时如果标签之间有大量空白,它就会爆炸。

4

4 回答 4

2

我要尝试的第一件事是使所有量词具有所有格并使所有组原子:

"@</?+(?![bisa]\b)(?!em\b)[^>]*+>
(?>[^<]++|</?+(?>(?>[bisau]|em|strong|sup)\b)[^>]*+>)*+
[?!.]+
@ix"

我认为 Jeremy 是对的:不是回溯本身会杀死你,而是正则表达式引擎必须保存的所有状态信息才能使回溯成为可能。正则表达式的构造方式似乎是,如果它不得不回溯,无论如何它都会失败。所以使用所有格量词和原子组,不要费心保存所有无用的信息。

编辑:为了允许句子结尾的标点符号,您可以在第二行添加另一种替代方法:

(?>[^<?!.]++|(?![^?!.\s<]++<)[?!.]++|</?+(?>(?>[bisau]|em|strong|sup)\b)[^>]*+>)*+

添加匹配一个或多个所述字符,除非它们是元素中的最后一个非空白字符。

于 2009-11-12T16:06:54.207 回答
1

我相当确定,甚至更新版本的 PHP 都与已知段错误问题的 PCRE 7.0 捆绑在一起。我不认为有任何纠正这个问题的意图,因为它在技术上是一个 PCRE 问题,而不是 PHP 的问题。

如果您告诉我们您正在尝试完成什么,那么您最好的选择是尝试编写一个替代表达式。

有问题的错误是:http ://bugs.php.net/bug.php?id=40909

于 2009-11-12T16:20:50.733 回答
0

您的正则表达式会导致大量回溯。中间有 10000 个字符,它会变得非常混乱和缓慢。不过,我不希望它崩溃......!

于 2009-11-12T14:52:33.267 回答
0

这仍然做你想要的吗?

</?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags
(?:(?>[^<\?\!\.]*)|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* #allow text and some inline tags
[\?\!\.]+
于 2009-11-12T14:44:03.503 回答