PHP编写BBCODE解析器时多层quote标签正则匹配错误如何解决
多层嵌套BBCode quote标签解决方案
问题原因
你当前使用的非贪婪匹配正则/\[quote\](.*?)\[\/quote\]/会优先匹配距离起始标签最近的结束标签,遇到嵌套场景时,会把内层的[quote]当做普通文本处理,直接匹配到第一个[/quote]就停止,导致外层的结束标签残留,匹配结果不符合预期。
解决方案1:循环替换(推荐,逻辑简单易维护)
循环执行替换逻辑,每次优先处理最内层没有其他嵌套的quote标签,直到没有可替换的quote标签为止,代码如下:
$text = '[quote] [quote] [quote] text [/quote] [/quote] [/quote]'; $pattern = "/\[quote\](.*?)\[\/quote\]/s"; $replacement = "<div class='quote'><div class='quotetext'>$1</div></div>"; do { $text = preg_replace($pattern, $replacement, $text, -1, $count); } while ($count > 0);
注:正则末尾加
s修饰符是为了让.可以匹配换行符,避免quote内容带换行时匹配失败。
解决方案2:递归正则一次性匹配
使用PCRE的递归语法(?R)实现嵌套结构的一次性匹配,代码如下:
$text = '[quote] [quote] [quote] text [/quote] [/quote] [/quote]'; $pattern = "/\[quote\]((?:[^[]++|\[(?!\/quote\])|(?R))*)\[\/quote\]/s"; $replacement = "<div class='quote'><div class='quotetext'>$1</div></div>"; $text = preg_replace($pattern, $replacement, $text);
正则逻辑说明:
[^[]++:匹配所有非[的字符,占有量匹配避免不必要的回溯\[(?!\/quote\]):匹配[后不是/quote]的内容,兼容其他BBCode标签和普通[字符(?R):递归套用整个正则规则,支持嵌套的quote结构
两种方案都可以完美处理多层嵌套的quote标签,循环替换方案调试修改成本更低,更适合大多数开发场景。
内容的提问来源于stack exchange,提问作者Timberman
相关产品推荐
相关产品推荐

