如何在输出嵌套格式标记上捕获和格式化



我正在开发一个论坛系统,该系统解析类似[b]some bold text[/b]的BBCode,并在通过PHP输出时对其应用HTML格式。我所有的表达式都能工作,但我很难弄清楚如何处理特定的场景,特别是关于嵌套引号块的场景。

在论坛上,你可能会让一个用户引用另一个用户的话。我已经成功地格式化这个使用:

#[quote="(.*?);(w*?)"]s*(.*?)s*[/quote]#

调用preg_replace()替换为:

<blockquote id="quote-$2"><p>$3<br> - $1</p></blockquote>这是一个工作示例。

对于您可能在论坛上看到的一个真实示例,用户Stan想要引用John,并将其添加到文本区域以供提交:

[quote="John;2"]John's sentence[/quote] 
____________
Stan's reply

但是,如果约翰在帖子中引用了玛丽的话,会发生什么呢?

[quote="John;2"][quote="Mary;1"]Mary's sentence[/quote]John's sentence[/quote]
____________
Stan's reply

我的正则表达式将捕获除最后一个[/quote]之外的所有字符串,但即使我能够捕获整个字符串,我也不确定如何格式化它。理想情况下,我希望输出看起来像这样:

"Mary's sentence"          
- Mary
"John's sentence"
- John
__________________________
Stan's reply

在HTML:中

<blockquote id="quote-2">
<blockquote id="quote-1"><p>"Mary's sentence"<br> - Mary</p></blockquote>
<p>"John's sentence"<br> - John</p>
</blockquote> 
<p>Stan's reply</p>

我可以使用regex捕获和格式化重复的嵌套标签吗?如果有100个嵌套的引号块怎么办?显然,我可以写一个长得离谱、重复的表达(当然会有局限性(,但必须有更好的方法来解决这个问题。还有其他方法我应该用吗?

如果已经存在类似的问题,我很抱歉,但我已经看了很多关于SO的问题,仍然不确定我应该采取哪种方法。

这样做的目的是确保只匹配最里面的BB标记。匹配[quote[/quote]之间不包含其他[quote=的所有文本,并进行替换,直到找不到匹配为止。这也是基于这样一个假设,即您的实际标签内容中没有[quote=,但在大多数情况下这是真的。另一个假设是属性是"引号,并且里面不能有其他双引号。

所以,你可以使用

$s = '[quote="John;2"][quote="Mary;1"]Mary's sentence[/quote]John's sentence[/quote]';
$repl = '<blockquote id="quote-$2"><p>$3 <br> - $1</p></blockquote>';
$reg = '~[quote="([^"]*);(w*)"]s*((?:(?![quote=).)*?)s*[/quote]~si';
while (preg_match($reg, $s)) {
$s = preg_replace($reg, $repl, $s);
}
echo $s;
// => <blockquote id="quote-2"><p><blockquote id="quote-1"><p>Mary's sentence <br> - Mary</p></blockquote>John's sentence <br> - John</p></blockquote>

请参阅PHP演示。正则表达式是

'~[quote="([^"]*);(w*)"]s*((?:(?![quote=).)*?)s*[/quote]~si'

请参阅regex演示。

详细信息

  • [quote="-文字子字符串
  • ([^"]*)-捕获组1:除"之外的任何0+个字符
  • ;-冒号
  • (w*)-捕获组2:0+字字符
  • "]-文字子字符串
  • s*-0+空白
  • ((?:(?![quote=).)*?)-捕获组3:任何字符,尽可能少,不启动[quote=文本
  • s*-0+空白
  • [/quote]-一个字面[/quote]子字符串

漂亮的打印是一项额外的任务,这里提到了几个解决方案。

最新更新