
preg_match 提取【】内内容时括号要转义
PHP 正则里 [ 和 ] 是特殊元字符,直接写 /【.*】/ 会报错或匹配失败——因为正则引擎把它们当成了字符组定义。必须用反斜杠转义:\【 和 \】(注意:中文全角括号也要转义,不是英文的 [)。
常见错误现象:Warning: preg_match(): Compilation failed: missing terminating ] for character class,就是忘了转义右括号导致的。
- 使用场景:解析日志、模板占位符、注释标记(如
【用户ID】) - 正确写法:
preg_match('/\【(.*?)\】/', $str, $matches),$matches[1]是括号内内容 -
.*?比.*更安全,避免跨多个【】贪婪匹配 - 如果字符串含换行,记得加
s修饰符:/\【(.*?)\】/s
mb_ereg_replace 不支持非贪婪模式,别用它处理中文括号
mb_ereg_replace 是 PHP 已废弃函数(自 7.4 起不推荐),且它的正则引擎不支持 ? 非贪婪语法,写 \【(.*?)\】 会直接忽略 ?,变成贪婪匹配,容易吃掉中间所有内容。
性能与兼容性影响明显:不仅功能受限,还可能在 PHP 8+ 环境彻底报错或静默失败。
立即学习“PHP免费学习笔记(深入)”;
- 替代方案只有
preg_match/preg_match_all(带u修饰符处理 UTF-8) - 必须加
u修饰符:/\【(.*?)\】/u,否则中文括号可能匹配失败 - 别依赖
mb_ereg系列函数,它们对 Unicode 支持弱,边界判断也不稳定
提取多个【】内容要用 preg_match_all,不是 preg_match
preg_match 只找第一个匹配项,遇到 文本【A】中间【B】结尾【C】 这种情况,只返回 A;真正要全量提取得用 preg_match_all。
参数差异关键点:第三个参数是引用传入的 $matches,结构是二维数组,$matches[0] 是完整匹配,$matches[1] 才是括号捕获的内容列表。
- 实操写法:
preg_match_all('/\【(.*?)\】/u', $str, $matches); $result = $matches[1] ?? []; - 空匹配要判
isset($matches[1]),否则$matches[1]可能未定义 - 如果只要去重后的结果,用
array_unique($matches[1]),但注意保持顺序需加SORT_REGULAR
正则无法覆盖嵌套【】或不闭合情况
标准正则不支持递归匹配,像 【外层【内层】结束】 这种嵌套结构,preg_match_all 会拆成 【外层【内层】 和 结束】 两段,逻辑上就错了。同样,【未闭合 会导致后续所有内容被吃到末尾。
这不是写法问题,是正则能力边界。真有这类需求,得换思路:
- 用字符串遍历 + 计数器手动解析(开括号 +1,闭括号 -1,值为 0 时截断)
- 若来自可信输入(如配置文件),优先改用 JSON/YAML 等结构化格式
- 临时 workaround:先用
str_replace把嵌套的【】替换成其他标记,再正则,但不可靠
最容易被忽略的是:没人告诉你正则根本处理不了嵌套——直到线上数据突然多出半个【或者漏掉一整段。这时候翻文档不如直接写个 while 循环扫一遍字符串。











