必须加 u 修饰符,否则中文正则如 \x{4e00} 或 \p{Han} 无法正常解析;文件需 UTF-8 无 BOM 编码;推荐用 /^\p{Han}+$/u 验证纯中文,注意全链路 UTF-8 一致性。

不加 u 修饰符,所有中文正则都失效——不是“可能不工作”,而是根本不会按你预期的方式解析 \x{4e00} 或 \p{Han}。
preg_match 匹配中文返回 false 的最常见原因
现象:preg_match('/[\x{4e00}-\x{9fa5}]+/', '你好') 永远返回 false,哪怕字符串确实是 UTF-8 编码的中文。
- 根本原因是 PCRE 引擎默认按字节处理,
\x{4e00}这种 Unicode 码点写法在无u时被当成非法转义,直接编译失败或静默跳过 - PHP 会抛出 warning(如
Warning: preg_match(): Compilation failed: PCRE does not support \L, \l, \N, \U, or \u),但很多环境关闭了 warning 显示,导致你以为“没匹配到”其实是“根本没编译成功” - 文件本身必须是 UTF-8 无 BOM 编码;如果编辑器存成了 GBK,源码里的
\x{4e00}可能被读成乱码字节,正则还没运行就已损坏
/^\p{Han}+$/u 是比 [\x{4e00}-\x{9fa5}] 更推荐的写法
\p{Han} 是 Unicode 属性类,覆盖简体、繁体、日文汉字、韩文汉字及大量扩展生僻字(如《康熙字典》用字),而 [\x{4e00}-\x{9fa5}] 仅覆盖基本平面常用汉字(约 2 万字),漏掉 \x{3400}-\x{4dbf}(扩展 A)、\x{20000}-\x{2a6df}}(扩展 B)等区块。
- 必须配
u修饰符,否则\p{Han}直接报错或退化为字面量p{Han} - 验证“纯中文字符串”:用
/^\p{Han}+$/u;验证“含中文”只需/\p{Han}/u(去掉^、$和+) - 若需兼容老环境(如某些嵌入式 PHP 编译未启用 PCRE Unicode 支持),回退到
[\x{4e00}-\x{9fa5}\x{3400}-\x{4dbf}]++u,但注意顺序无关,别漏u
匹配中文 + 字母 + 数字时的边界陷阱
业务中常写 /^[a-zA-Z0-9\x{4e00}-\x{9fa5}]+$/u 验证用户名,但容易忽略两个关键点:
立即学习“PHP免费学习笔记(深入)”;
- 首字符限制:如果要求“字母或汉字开头”,不能只靠
^+ 字符组,得拆成/^[a-zA-Z\x{4e00}-\x{9fa5}][a-zA-Z0-9\x{4e00}-\x{9fa5}]*$/u - 空格和下划线:中文场景常允许下划线,但
_要显式加入字符组,不能依赖\w(它在u模式下虽包含汉字,但行为不稳定,且不含下划线) - 量词长度控制:用
{2,16}替代+,避免超长字符串拖慢回溯;PCRE 对 Unicode 字符组的回溯开销比 ASCII 高得多
排除中文字符的写法容易反向翻车
想“剔除字符串中所有中文,只留英文数字标点”,常误写成 /[^\x{4e00}-\x{9fa5}]/u —— 这个正则本身没错,但用错函数就会出问题。
-
preg_replace('/[^\x{4e00}-\x{9fa5}]/u', '', $str)是**保留中文、删其他**,因为[^...]表示“非中文”,替换为空就是删非中文 - 若想**删中文、留其他**,应写
preg_replace('/[\x{4e00}-\x{9fa5}]/u', '', $str) - 更安全的剔除方案是用
preg_replace('/\p{Han}/u', '', $str),语义清晰,且自动覆盖扩展汉字区
真正容易被忽略的是全链路 UTF-8 一致性:数据库连接、HTTP 请求头、HTML 响应头、PHP 文件编码、甚至 IDE 的保存设置,任一环节是 GBK 或 Latin-1,u 修饰符就只是徒有其表。



















