我目前正在创建bbcode解析引擎,遇到了一个我自己无法弄清楚的情况。
问题是,我突然遇到了一个与此完全相同的问题: Apache / PHP on Windows crashes with regular expression
这意味着,如果我执行类似下面示例的操作,Apache 会因为递归计数达到 690(PCRE 的内存限制为 1MB)而崩溃:
$txt = '[b]'.str_repeat('a', 338).'[/b]'; // if I change repeat count to lower value it's ok
$regex = '#\[(?P<attributes>(?P<tag>[a-z0-9_]*?)(?:=.*?|\s.*?|))](?P<content>(?:[^[]|\[(?!/?(?P=tag)])|(?R))+?)\[/(?P=tag)]#mi';
echo preg_replace_callback($regex, function($matches) { return $matches['content']; }, $txt);
所以我需要以某种方式最大限度地减少正则表达式中 *
和 +
的需求,但这就是我没有想法的地方,所以我想也许你可以提出一些建议.
欢迎使用其他解析 bbcode 的方法(可以处理嵌套标签)。 但是我不想使用已经构建的类或其他东西。我喜欢自己做事!
我还研究了 PECL 和 Pear HTML_BBCodeParser。但我不希望我的应用程序依赖于扩展。更有可能的是,我可能会执行一些脚本来检查该扩展名,如果它不存在,则使用我在这里尝试执行的 BBCode 解析器。
抱歉,如果我的描述令人沮丧,我不擅长英语^^
编辑。所以正则表达式解释道:
\[(?P<attributes>(?P<tag>[a-z0-9_]*?)(?:=.*?|\s.*?|))]
这是我的开始标签。我使用了命名组。使用“标签”我识别标签,使用“属性”我识别标签属性。也可以将标签视为属性。那么这里发生了什么?我尝试匹配一个标签,当一个标签匹配时,我尝试匹配 =
符号之后的任何内容或 \s
(间隔符)之后的任何内容,直到达到标签闭合 ]
。
(?P<content>(?:[^[]|\[(?!/?(?P=tag)])|(?R))+?)
现在我正在尝试匹配内容。这是棘手的部分。我正在寻找任何不是 [ 的字符,如果找到任何字符,那么我检查它是否不是我的结束标记或递归,然后我告诉正则表达式引擎这样做,直到......
\[/(?P=tag)]
...找到结束标记。
最佳答案
您的正则表达式,尤其是零宽度断言(环视)会导致正则表达式引擎灾难性地回溯。这个故事的寓意是:正则表达式不能不应该用于解析不规则的语言。如果您有嵌套结构,那么这不是常规语言。
事实上,我认为 BBCode 是邪恶的。 BBCode 是一种由懒惰的程序员发明的标记语言,他们不想以正确的方式过滤 HTML。结果,我们现在有一个松散的“标准”,很难实现。以正确的方式过滤 HTML:
关于php - 由于 PCRE 限制,正则表达式导致 Apache 崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3613121/