对于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;
这适用于我上面的例子(非嵌套的blockquotes)。 然而,如果块引用是嵌套的,例如在以下示例中:
<blockquote rel="blah">foo <blockquote rel="bloop">bar ...maybe another nest...</blockquote></blockquote>
它不起作用。所以我的问题是,如何使用regex / PHP的组合替换所有嵌套块引用?我知道在(?R)
的PHP中可以使用递归模式;以下正则表达式将从包含它们的字符串中提取所有嵌套的块引用:
/(<blockquote rel="([\d\w_ ]{3,30})">)(.*|(?R))(<\/blockquote>)/s
但是从那时起,我不太清楚在preg_replace_callback()
回调中如何处理,用上面的替换来替换每个嵌套的blockquote。
任何帮助都将不胜感激。
答案 0 :(得分:6)
简单的答案是你不能用正则表达式做到这一点。任意深度的嵌套标签(或parens,括号或任何东西)的语言不是常规,因此无法与常规表达式匹配。我建议您使用DOM解析器,或者 - 如果出于某种奇怪的原因绝对必要 - 编写自己的解析方案。
复杂的答案是你可能能够使用一些非常丑陋,hacky的正则表达式和PHP代码来做到这一点,但我不建议它说实话。
另请参阅:The Chomsky hierarchy。
另见:
答案 1 :(得分: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);