平面划分与用途
Unicode 把 0 到 0x10FFFF 的码位空间切成 17 个平面,每平面 65536 个码位。平面 0(基本多文种平面 BMP)承载最常用字符;平面 1(补充多文种平面)放 emoji、音乐与数学符号、古文字;平面 2(补充表意文字平面)是 CJK 扩展区,绝大多数生僻汉字在此;平面 3 也有 CJK 扩展后缀区;平面 14 用于变体选择符等特殊用途;平面 15 与 16 是私用区,留给应用自行约定。平面内的「区块」是连续码位区间,用于分类与文档归类。
基本信息
| 总平面数 | 17 个,每平面 65536 个码位 |
|---|---|
| 平面 0 | 基本多文种平面(BMP),U+0000-U+FFFF |
| 平面 1 | 补充多文种平面,含 emoji 与大量符号、古文字 |
| 平面 2 / 3 | 补充表意文字平面,CJK 扩展区与生僻汉字 |
| 平面 14 | 特殊用途区,如变体选择符与标签字符 |
| 平面 15 / 16 | 私用区,码位含义由应用自行定义 |
典型使用场景
- 判断字符是否在 BMP 内:直接影响 UTF-16 下占 1 个还是 2 个编码单元
- 生僻字处理:人名与地名中的扩展区汉字常位于平面 2,系统不支持时会出现替换符
- emoji 支持度评估:存储与传输链路是否支持平面 1 决定 emoji 能否完整保存
- 字体覆盖规划:字体通常只覆盖部分平面,缺失时会显示为方块
- 正则与校验规则:按码位区间判断字符类别比列字符清单可靠
判断所属平面
判断所属平面
python -c "print(hex(ord('中')), hex(ord('\U0001F600')), hex(ord('\U00020000')))" # 0x4e2d / 0x1f600 / 0x20000
python - <<'EOF'
# 按码位判断所属平面(0 为 BMP,1 为 SMP,2 为 SIP,依此类推)
for c in '中\U0001F600\U00020000':
cp = ord(c)
print(hex(cp), 'plane', cp >> 16)
EOF
python -c "print(len('\U0001F600'.encode('utf-16-le')))" # 4 字节:说明它占两个 UTF-16 编码单元平面速查
| 平面 | 码位范围 | 主要内容 |
|---|---|---|
| 0(BMP) | U+0000-U+FFFF | 常用汉字、拉丁字母、常用符号 |
| 1(SMP) | U+10000-U+1FFFF | emoji、音乐符号、数学字母、古文字 |
| 2(SIP) | U+20000-U+2FFFF | CJK 扩展 B 及之后的大批生僻汉字 |
| 3(TIP) | U+30000-U+3FFFF | 后续 CJK 扩展区 |
| 14(SSP) | U+E0000-U+EFFFF | 变体选择符、标签字符等特殊用途 |
| 15 / 16(PUA) | U+F0000-U+10FFFD | 私用区,含义由应用约定 |
「区块」与「是否可打印」不是一回事:区块只是码位的连续区间划分,同一区块内既有可打印字符也可能有未分配码位,随 Unicode 版本持续更新。做字符分类时应依据官方属性(如通用类别)而不是区块边界。
私用区不是通用存储方案:把自定义字形塞进私用区后,文件在别的系统或字体下会显示为方块或错误字符,且无法与其他系统交换含义。仅限封闭环境内部使用,并能随附字体与映射约定。
BMP 边界非常实用:BMP 内字符在 UTF-16 下占 1 个编码单元,增补平面字符占 2 个并需要代理对。很多旧系统与分析脚本的「按两个字节处理」假设都建立在这个边界上,遇到平面 1、2 的字符就会出错。