正则表达式不能可靠验证JSON有效性,仅适合提取候选片段;必须用json_decode()进行最终验证。

为什么 preg_match('/{.*}/') 会部分匹配
这个正则只检查字符串里有没有一对花括号,不管里面是不是合法 JSON。比如 "{ \"name\": }"、"abc{ \"x\": 1 }def"、甚至 "{ \"a\": \"b\" , \"c\": "(缺结尾)都会匹配成功——它根本没验证结构完整性。
preg_match 必须加锚点和修饰符
不加 ^ 和 $ 就等于放任匹配子串;不加 s 修饰符,. 就无法跨行匹配换行符,而真实 JSON 常含缩进和换行。
- 错误写法:
preg_match('/{.*}/', $json)→ 匹配任意位置的{...} - 正确写法:
preg_match('/^\{.*\}$/s', $json)→ 强制从头到尾,且.覆盖换行 - 但仅这样仍不够:无法识别未闭合引号、嵌套错位、非法字符等
真正可靠的验证只能靠 json_decode()
PCRE 递归正则(如 (?(DEFINE)... 那种)理论上能覆盖 JSON 规范,但在 PHP 中极易因回溯爆炸失败,且不同 PCRE 版本兼容性差,调试成本远高于直接解析。
- 必须用
json_decode($json, null, 512, JSON_THROW_ON_ERROR)或手动检查json_last_error() - 如果非要前置过滤(比如日志中混有非 JSON 文本),先用正则粗筛出疑似 JSON 片段,再对每个片段调用
json_decode() - 示例粗筛:
preg_match('/\{(?:[^{}]|(?R))*\}/', $text, $m)—— 但该模式依赖 PCRE recursion,PHP 8.0+ 才稳定,且仍可能漏判或误判
正则只适合“提取”,不是“验证”
如果你的目标是确认一段文本是否为有效 JSON,就别碰正则。它唯一安全的用途是:从 HTML、日志、JSONP 包裹中切出候选字符串,然后交给 json_decode() 做最终判决。
立即学习“PHP免费学习笔记(深入)”;
- JSONP 剥离:
preg_replace('/^\w+\((.*)\);?$/s', '$1', $jsonp),之后必须json_decode() - HTML 中提取:
preg_match('/var\s+data\s*=\s*(\{.*?\});/s', $html, $m),再对$m[1]解码 - 任何正则结果都只是“可能 JSON”,不是“确定 JSON”
最常被忽略的一点:即使正则看起来匹配了完整结构,只要 JSON 里有 "key": "value with \n or \u4f60" 这类转义,纯正则就大概率失效——而 json_decode() 天然处理这些。



















