本文详解如何用正则表达式与循环替换策略,精准处理多层嵌套的 `[code=xxx]...[/code]` bbcode 标签,避免截断或错配,确保深层嵌套内容被完整、安全地提取或转换。
在 PHP 中实现 BBCode 解析时,最常见也最容易出错的问题之一就是同名标签的嵌套处理——例如 [code=php]...[code=js]...[/code]...[/code]。原始正则 #\[(code)=(.*?)\](.*?)\[/\1\]#si 采用贪婪匹配,仅能捕获最外层到第一个 [/code] 的内容,导致内层标签被当作普通文本残留,最终解析失败。
为支持任意深度嵌套(如 [code]A[code]B[/code]C[/code]),需满足两个核心
要求:
推荐使用以下正则(带注释):
$pattern = '~\[code=([^]]*)]([^[]*(?:\[(?!/code]|code=)[^[]*)*)\[/code]~';
关键设计解析:
⚠️ 注意:该正则仅匹配一层(最内层),因此必须循环执行直到无替换发生,才能完全展开所有嵌套:
function parseNestedCode($text) {
$count = 0;
do {
$text = preg_replace(
'~\[code=([^]]*)]([^[]*(?:\[(?!/code]|code=)[^[]*)*)\[/code]~i',
'$2',
$text,
-1,
$count
);
} while ($count > 0);
return $text;
}
// 测试用例
$content = '[code=php]test message [code=js]console.log("hello");[/code] and more[/code]';
echo parseNestedCode($content);
// 输出:test message console.log("hello"); and more若环境支持,可启用 (?R) 递归子模式,单次匹配即可处理任意深度:
$pattern = '~\[code=([^]]*)]((?:(?!\[/?code\b).|(?R))*)\[/code]~si';
$result = preg_replace($pattern, '$2', $content);✅ 优势:简洁、一次到位;
⚠️ 风险:(?R) 在复杂嵌套下可能栈溢出,且部分旧版 PHP(生产环境建议优先使用迭代法。
通过上述方法,你不仅能彻底解决 [code] 嵌套解析问题,更能构建一个健壮、可维护的 BBCode 解析器基础框架。