中文字符匹配的编码前提
匹配汉字之前要先确定三件事:字符串在内存里是按字节还是按字符处理、引擎是否支持 Unicode 字符属性、需要覆盖哪些汉字范围。常见写法「从 4E00 到 9FA5 的区间」只覆盖统一表意文字基本区,扩展区的生僻字与部分兼容字会被判为非法,是中文姓名校验里最常见的误拒来源。
基本信息
| 推荐写法 | 按 Unicode 脚本属性匹配汉字,各引擎写法不同,需带相应的标志或选项 |
|---|---|
| 区间写法 | 4E00 到 9FFF 覆盖基本区与部分扩展,仍不含扩展 B 及以后的补充平面 |
| 易漏字符 | 扩展区汉字、兼容表意文字、中文数字〇、以及中文标点(逗号句号叹号等属其他区块) |
| 编码影响 | 按字节处理时一个汉字占多字节,长度统计与区间判断都会失真 |
典型使用场景
- 姓名校验:要允许生僻字,只写基本区区间会把部分真实姓名判为非法
- 中文分词与抽取:按脚本属性界定范围比拼区间更完整
- 昵称与评论过滤:需要同时判断中文字符、字母、数字与允许的标点
- 字段长度校验:按字符数而非字节数计长度,否则中文内容长度判断错误
- 文本清洗:区分汉字与中文标点,统计和截断时分别处理
各引擎写法与实测
各引擎写法与实测
# JavaScript:必须带 u 标志,且属性要写完整的脚本名
/\p{Script=Han}/u.test('中') // true
/\p{sc=Han}/u.test('中') // true,缩写形式
/\p{Han}/u.test('中') // 会报属性名非法,不要用
/\p{Han}/.test('中') // false;不带 u 时会被当成字面文本匹配
# Python:标准库 re 不支持属性转义,需手写区间或改用第三方库
re.compile(r'[\u4e00-\u9fff]+') # 手工区间,注意覆盖范围有限
# PHP PCRE:/u 下可直接用属性名
/^\p{Han}+$/u
# Java:用 IsHan 或 script=Han 形式
Pattern.compile("^\\p{IsHan}+$")写法与覆盖范围
| 写法 | 覆盖范围 | 适用场合 |
|---|---|---|
| 按脚本属性 | 按其脚本归属的全部汉字 | 通用场景,需引擎支持 |
| 基本区区间 | 4E00 到 9FFF | 仅需覆盖常用字 |
| 扩展到补充平面 | 含各扩展区 | 生僻字、古籍与专业用字 |
| 字节范围形式 | 按编码字节分布 | 旧编码环境,易误伤符号 |
字符长度与字节长度是两件事:按字节数做字段上限时,中文内容的可用长度约为按字符计时的三分之一,数据库字段类型与校验规则必须换算一致,否则入库会被截断。
中文标点不属于汉字脚本:逗号、句号、书名号等各自属于其他区块,中文数字〇也在另一位置。做「纯中文」校验时要明确是否允许标点、字母与间隔号,少数民族姓名中常见的间隔号需要单独放行。