【问题标题】:Bbcode parser does not work correctlyBbcode 解析器无法正常工作
【发布时间】:2017-08-06 14:39:31
【问题描述】:

我对 BBCodes 有疑问 - 此 preg_replace 无法按预期工作:

$message = preg_replace("/\[color=(\#[0-9A-F]{6}|[a-z]+)\](.*)\[\/color\]/Usi", "<span style=\"color:\\1\">\\2</span>", $message);

这可以正常工作:

[color=#ff0000]text text text text text[/color]
[color=#00ffff]texttexttext[/color]

结果:

但是如果有两个颜色标签一个接一个,就不能正常工作了:

[color=#ff0000][color=#00ffff]text text text text text[/color] [/color]

[color=#ff0000]text text text[color=#00ffff]text text text text text[/color] [/color]

结果:

【问题讨论】:

标签: php regex bbcode


【解决方案1】:

您也可以通过 2 次替换来做到这一点。一个用于开始标签,一个用于结束标签。

那么这些颜色标签的嵌套就无关紧要了。

$message = preg_replace('%\[color=(\#[0-9A-F]{6}|[a-z]+)\]%i', '<span style="color:$1">', $message);

$message = preg_replace('%\[/color\]%i', '</span>', $message);

或在 1 个语句中:

$message = preg_replace(
[   '%\[color=(\#[0-9A-F]{6}|[a-z]+)\]%i',
    '%\[/color\]%i'
],
[   '<span style="color:$1">',
    '</span>'
], $message);

正如Casimir et Hippolyte 所指出的,不考虑嵌套可能会产生不好的结果。

所以这是另一种使用while循环和递归正则表达式的方法:

$pattern = '%\[color=(\#[0-9A-F]{6}|[a-z]+)\].*?(((?R)|.)*?)\[\/color\]%i';   
$replacement = '<span style="color:$1">$2</span>';

do {
    $message = preg_replace($pattern, $replacement, $message, -1, $count);
} while ($count);

【讨论】:

  • 这是个坏主意,因为如果用户输入格式错误的 bbcode,例如:[color=#BBCC99]text[/color][/color][/color],所有关闭的 [/color] 标记都将替换为关闭的 &lt;/span&gt; 标记,从而导致 html 格式错误。预期的行为是不平衡和格式错误的 bbcode 标签不会被替换(然后用户可以看到它们并进行编辑)。
  • 为了解决这个问题,您可以在do...while循环中使用只描述最内层平衡bbcode标签的模式,并使用preg_replacecount参数来停止循环。跨度>
  • @CasimiretHippolyte 你是对的。用户可能会弄​​乱这些标签。所以我添加了一个考虑嵌套到答案的解决方案。
  • 干得好,但是描述最里面的 bbcode 标签比编写递归模式来获取最外面的标签更简单。
【解决方案2】:

实际上,在字符串[color=#ff0000][color=#00ffff]text text text text text[/color] [/color] 中,您的正则表达式匹配第一个开头和第一个结束标记。避免这种情况的一种方法是稍微修改您的正则表达式,例如:

/\[color=(\#[0-9A-F]{6}|[a-z]+)\]([^[]*)\[\/color\]/

那么它只会匹配嵌套最多的标签。您需要在循环中执行此操作,而您的字符串包含 bbcodes。

【讨论】:

  • 你的想法是 IMO 的好主意。*(匹配最嵌套的标签,并使用循环)*。然而,遗憾的是只显示模式而不是完整的 php 代码以及您正在谈论的循环。顺便说一句,使用[^[] 过于严格,因为它还禁止使用除颜色标签以外的标签。但是您对原始模式的想法有效。如果您想要一个允许其他标签的贪婪模式,您可以将[^[]* 替换为[^[]*(?:\[(?!/?color\b)[^[]*)*。您的模式也有许多反斜杠。为了避免它们,将分隔符更改为 ~ 并删除 #/] 之前的反斜杠。添加 i 修饰符。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-20
  • 2017-04-30
  • 2021-11-25
  • 2021-08-10
  • 1970-01-01
  • 2019-10-09
相关资源
最近更新 更多