如何捕获输出的嵌套格式标签并对其格式化?

时间:2018-07-23 04:48:01

标签: php regex nested forum

我正在开发一个论坛系统,该系统可解析[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>这是working example

举一个真实的例子,您可能在论坛上看到一个用户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>

我可以使用正则表达式捕获和格式化重复的嵌套标签吗?如果有100个嵌套的报价块怎么办?显然,我可以写一个荒谬而冗长的重复表达式(肯定会有局限性),但是必须有一种更好的方法来解决这个问题。我应该使用另一种方法吗?

对于similar question already exists,我感到很抱歉,但是我在SO上浏览了许多问题,但仍不确定应该采用哪种方法。

1 个答案:

答案 0 :(得分:1)

这个想法是确保您只匹配最里面的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 demo。正则表达式是

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

请参见regex demo

详细信息

  • \[quote="-文字子字符串
  • ([^"]*)-捕获第1组:"以外的任意0+个字符
  • ;-冒号
  • (\w*)-捕获第2组:0个以上的字符字符
  • "]-文字子字符串
  • \s*-超过0个空格
  • ((?:(?!\[quote=).)*?)-捕获第3组:尽可能少的任何字符,而不以[quote=文本开头
  • \s*-超过0个空格
  • \[/quote]-文字[/quote]子字符串。

漂亮打印是一项额外的任务,其中有a couple of solutions mentioned here