2

我对 PHP 和正则表达式一无所知,但我正在尝试为我的论坛修复一个损坏的插件。

我想替换以下内容:

<blockquote rel="blah">foo</blockquote>

<blockquote class="a"><div class="b">blah</div><div class="c"><p>foo</p></div></blockquote>

实际上,这部分很简单,我已经部分修复了插件来做到这一点。以下正则表达式用于调用以preg_replace_callback()进行替换:

/(<blockquote rel="([\d\w_ ]{3,30})">)(.*)(<\/blockquote>)/u

回调代码为:

return <<<BLOCKQUOTE
<blockquote class="a"><div class="b">{$Matches[2]}</div><div class="c"><p>{$Matches[3]}</p></div></blockquote>
BLOCKQUOTE;

这适用于我上面的示例(非嵌套块引用)。但是,如果块引用是嵌套的,例如在以下示例中:

<blockquote rel="blah">foo <blockquote rel="bloop">bar ...maybe another nest...</blockquote></blockquote>

它不起作用。所以我的问题是,如何使用正则表达式/PHP 的组合替换所有嵌套的块引用?我知道在 PHP 中递归模式是可能的(?R);以下正则表达式将从包含它们的字符串中提取所有嵌套的块引用:

/(<blockquote rel="([\d\w_ ]{3,30})">)(.*|(?R))(<\/blockquote>)/s

但是从那里开始,我不太确定在preg_replace_callback()回调中做什么来用上面的替换替换每个嵌套的块引用。

任何帮助,将不胜感激。

4

2 回答 2

6

简单的答案是你不能用正则表达式来做到这一点。任意深度的嵌套标签(或括号、括号或任何东西)的语言不是正则的,因此不能与正则表达式匹配。我建议您使用 DOM 解析器,或者 - 如果出于某种奇怪的原因绝对必要的话 - 编写自己的解析方案。

复杂的答案是,您可能可以使用一些非常丑陋、hacky 的正则表达式和 PHP 代码来做到这一点,但我不建议您老实说。

另见:乔姆斯基层次结构

另见:

于 2010-10-17T01:37:22.363 回答
0

没有对递归替换的直接支持,preg_replace_callback()在这种情况下也不是特别有用。但是没有什么能阻止你多次进行替换。第一次通过处理最外面的标签,随后的通过向内工作。可选$count参数告诉您在每次传递中执行了多少次替换;当它为零时,你就完成了。

$regex = '~(<BQ rel="([^"]++)">)((?:(?:(?!</?+BQ\b).)++|(?R))*+)(</BQ>)~s';
$sub = '<BQ class="a"><div class="b">$2</div><div class="c"><p>$3</p></div></BQ>';
do {
  $s = preg_replace($regex, $sub, $s, -1, $count);
} while ($count != 0);

在 ideone.com 上查看它的实际应用

于 2010-10-17T03:59:22.480 回答