PHP正则匹配中文必须加u修饰符,否则\x{4e00}-\x{9fa5}或\p{Han}均失效;推荐用/\p{Han}+/u替代宽泛Unicode范围,需确保文件UTF-8编码且环境全链路UTF-8一致。

PHP 正则匹配中文,核心就一条:必须加 u 修饰符,且 Unicode 范围写法要对;不加 u,[\x{4e00}-\x{9fa5}] 这类写法直接失效或报错。
preg_match 匹配中文时为什么总返回 false?
常见现象是 preg_match('/[\x{4e00}-\x{9fa5}]+/', $str) 永远不命中,哪怕字符串确实是“你好”。根本原因是没加 u 修饰符——PCRE 引擎默认按字节处理,无法识别 UTF-8 多字节序列。
-
u不是可选,是强制要求;漏掉会触发 warning 或静默失败 - 文件本身必须存为 UTF-8 编码(无 BOM),否则源码里的
\x{4e00}可能被解析成乱码 - 若用
\p{Han}(推荐替代方案),更简洁但同样依赖u,且需 PHP 环境启用 PCRE Unicode 支持 - 错误示例:
preg_match('/^\p{Han}+$/', '你好')→ 缺u,匹配失败;正确写法:preg_match('/^\p{Han}+$/u', '你好')
验证“纯中文字符串”和“含中文字符串”的区别
业务中常混淆这两者:“只含中文”是全字符都属汉字,“含中文”只要出现一个就算。正则边界和量词决定语义。
- 全中文(不含空格/标点):
/^[\x{4e00}-\x{9fa5}]+$/u或更准的/^\p{Han}+$/u - 含中文(至少一个):
/[\x{4e00}-\x{9fa5}]/u—— 不需要^和$,也不需要+ - 允许中文+字母+数字:
/^[\x{4e00}-\x{9fa5}a-zA-Z0-9]+$/u;注意顺序无关,但别漏掉u - 排除中文:
/^[^\x{4e00}-\x{9fa5}]*$/u,注意^在字符组内表示“非”,不是行首
为什么 \p{Han} 比 \x{4e00}-\x{9fa5} 更可靠?
\x{4e00}-\x{9fa5} 是常用汉字区间,但漏掉扩展 A/B 区(如“?”、“㐀”)、部首、标点等;\p{Han} 是 Unicode 标准定义的“汉字脚本”(Han script),覆盖更全,且无需记忆码点。
立即学习“PHP免费学习笔记(深入)”;
- 支持前提:PHP 编译时 PCRE 启用了 Unicode 属性(现代发行版基本默认开启)
- 验证是否可用:
var_dump(pcre_version());查看版本,若含 “Unicode property support” 即可 - 性能差异极小,但可读性高:
/\p{Han}+/u比/[\x{4e00}-\x{9fa5}\x{3400}-\x{4dbf}\x{20000}-\x{2a6df}}]+/u简洁得多 - 注意:
\p{Han}不包含全角 ASCII 符号(如,。!)、日文平假名/片假名,它们属于其他 Unicode 类别
替换或提取中文时 preg_replace / preg_match_all 的坑
批量操作比单次匹配更容易暴露编码问题,尤其涉及多字节字符截断或空格处理。
-
preg_replace('/[\x{4e00}-\x{9fa5}]+/u', '', $str)能安全删中文,但若目标字符串含混合编码(如 GBK 未转 UTF-8),结果不可控 - 提取所有中文片段用
preg_match_all('/\p{Han}+/u', $str, $matches),结果在$matches[0];别用mb_ereg系列,已废弃 - 避免贪婪陷阱:比如想匹配“中文+后跟一个英文单词”,写成
/\p{Han}+\s+[a-zA-Z]+\b/u,而非/\p{Han}+.+[a-zA-Z]+\b/u(中间.会跨行吞掉不该吞的内容) - 性能提示:中文正则本身不慢,但若在大文本中反复执行,建议先用
mb_strlen($str, 'UTF-8') > 0快速过滤空值,减少正则调用次数
最易被忽略的是环境一致性:PHP 文件编码、HTTP 请求字符集、数据库连接 charset、输出 header,四者不全是 UTF-8,u 修饰符也救不了——它只管正则引擎,不管数据从哪来、到哪去。



















