多维BBCODE

Multidimentional BBCODE

我正在努力使自己成为 PHP 中的 BBCODE 解析器。

现在我有以下正则表达式:

\[quote\](.*?)\[\/quote\]

这应该替换为:

<div class='quote'><div class='quotetext'></div></div>

这一切都很完美,直到我有一个“多维”post示例:

[quote] [quote] [quote] text [/quote] [/quote] [/quote]

这应该有以下结果:

<div class='quote'><div class='quotetext'>
      <div class='quote'><div class='quotetext'>
           <div class='quote'><div class='quotetext'>
           text
           </div></div>
      </div></div>
</div></div>

现在得到以下结果:

<div class='quote'><div class='quotetext'> [quote] [quote] text </div></div> [/quote] [/quote]

Php:

preg_replace("/\[quote\](.*?)\[\/quote\]/", "<div class='quote'><div class='quotetext'></div></div>", $text); 

我希望有人能帮我解决这个问题。谢谢

一次通过正则表达式方法:

  1. 构造一个数组,将 bbcode 标签与相应的 html 代码相关联。
  2. 编写一个能够匹配嵌套(或不匹配)引用 bbcode 标签的模式。利息将是双倍的,因为它只允许提取有效部分(平衡的),然后进行替换。
  3. 使用关联数组在回调函数中使用 strtr 进行简单替换。

Pro:这是相对较快的,因为它只需要一次传递并且因为使用了 strtr.
缺点:它不灵活,因为它只考虑 [quote] 而不是 [quote param="bidule"][QUOTE] 之类的标签。 (然而,没有什么可以禁止编写更详细的回调函数并稍微更改模式)。

$corr = [
    '[quote]' => '<div class="quote"><div class="quotetext">',
    '[/quote]' => '</div></div>'
];

$pat = '~ \[quote]
          # all that is not a quote tag
          (?<content> [^[]*+ (?: \[ (?! /?quote] ) [^[]* )*+ )
          # an eventual recursion ( (?R) is a reference to the whole pattern)
          (?: (?R) (?&content) )*+
          \[/quote]
        ~x';

$result = preg_replace_callback($pat, fn($m) => strtr($m[0], $corr), $str);

多遍的更经典的方法:

  1. 构建一个禁止嵌套引号标签的模式,这样只会替换内部标签。
  2. 将替换放在一个 while 循环中,并在没有更多要替换的标签时停止它(使用 preg_replace 计数参数了解这一点)
$pat = '~ \[quote] ( [^[]*+ (?: \[ (?! /? quote] ) [^[]* )*+ ) \[/quote] ~x';
$repl = '<div class="quote"><div class="quotetext"></div></div>';

$result = $str;
$count = 0;

do {
    $result = preg_replace($pat, $repl, $result, -1, $count);
} while($count); 

pro:比第一种方法更灵活,因为您可以轻松更改模式和替换字符串。
缺点:明显较慢,因为您需要 n+1 循环,其中 n 是最大嵌套级别。


顺便说一句:当您只需要一个 html 标签并且 blockquote 标签存在时,您出于什么原因想要用两个 div 替换一个糟糕的 [quote] 标签!