算法与数据结构 / regex · Unicode 字符模型与一个自研引擎 / 不是用来写字的码点:边界、保留、私用与回退记号 待审核 9 / 36
码空间 · 特殊用意的码点

不是用来写字的码点:边界、保留、私用与回退记号

一面国旗在某些设备上只显示成两个字母方块,一个 U+10FFFF 是整个 Unicode 的最后一个码点——它们提醒我们:code point 不等于普通可见字符。码空间 U+0000 ~ U+10FFFF 里,有的码点是边界、有的永久保留给机制(代理区)、有的标准永不定义(私用区与非字符)、有的是控制或回退记号(替换符 �、bidi 反转、单用的 Regional Indicator)。

1 · 码点探针

输入或拖一个 code point(0 到 0x10FFFF),实时报它落在哪个区、是不是合法 scalar value、属不属于代理 / 非字符 / 私用,以及本浏览器的属性类怎么判它。

图 1-1 · 任意码点的身份判定与属性类实测。可拖滑块、输入 hex 或点预设,观察各区段的标签变化。

注 · scalar value 与 code point 不是一回事。代理区 U+D800 ~ U+DFFF 这 2048 个号是 code point,但不是 Unicode scalar value——它们专门留给 UTF-16 代理对 拼补充平面字符,单独出现不能合法编码。能正常出现在文本里的,是 scalar value,即全体码点减去代理区。

2 · 码空间地图

Unicode 码空间分成 17 个平面,每个平面 65536 个码点,共 1 114 112 个——尽头正是 U+10FFFF。大多数平面是文字,特殊用意的区段集中在几个平面里。

图 2-1 · 17 个平面的分布,带特殊区段的平面高亮标出。
表 2-1 · 特殊区段一览,连同 JS 属性类能不能认它。
范围 名称 gc 用途 JS 属性类
U+D800–U+DFFF High / Low Surrogates Cs UTF-16 代理对专用,单独非法 \p{Cs}
…FDD0–…FDEF 与每平面末 …FFFE/…FFFF Noncharacters(66 个) Cn 保留给程序内部,永不分配 \p{Noncharacter_Code_Point}
U+E000–U+F8FF Private Use Area Co 标准永不定义,留给私下约定 \p{Co}
U+F0000–U+FFFFD / U+100000–U+10FFFD Supplementary PUA-A / B Co 两整个平面的私用区 \p{Co}
U+FFFD Replacement Character � So 解码失败时的回退占位 普通符号
U+202A–U+202E / U+2066–U+2069 Bidi 方向控制 Cf 改变显示方向 → Trojan Source \p{Cf}
U+0000 / U+10FFFF 码空间首 / 尾 边界:第一个 / 最后一个码点

警示 · U+10FFFF 有双重身份:它既是码空间的最后一个码点,本身又是一个非字符(noncharacter)——每个平面最后两个码点(…FFFE / …FFFF)和 U+FDD0~U+FDEF 一起,共 66 个非字符,永久保留给程序内部当哨兵或标记,永不分配给真正的字符。

3 · 这些码点在 JS 里的真实行为

前两节讲的是「身份」,本节是「行为」——四个最常撞见的特殊码点,数值全是当场算出来的。

图 3-1 · 单用 Regional Indicator、孤儿代理、替换字符与 bidi 反转四种行为的现场读数。

4 · 番外:花钱「赞助」一个字符

一个常见误解:「私用区是不是 Unicode 卖给或留给赞助商的?」——不是。私用区是谁都能用的公共空白,标准只承诺永不在那里放官方字符,含义靠私下约定,没有谁能买断。真正和「赞助」有关的是另一件事:Unicode Consortium 的 Adopt a Character 募捐项目。

注 · Adopt a Character(认领一个字符)是给 Unicode 捐一笔款,「认领」一个早已编码、人人都在用的公共字符,换来一张电子徽章加证书和官网致谢——不会拿到 code point,也没有任何所有权,那个字符照旧属于标准、归大家共用。分三档:Gold $5,000(某字符唯一赞助人)、Silver $1,000(最多 5 人)、Bronze $100。所以它和私用区 PUA 是两码事:PUA 是「公共空白、私下约定」,Adopt 是「给标准组织捐款、领证书」。官方页面见 aac.unicode.org/adopt赞助人名单

建议 · 和别的页串起来看:代理区为什么是「孤儿」,见 字符的编码 的代理对换算;单用的 Regional Indicator 怎么两两拼成国旗,见 RGI 序列;零宽与 BOM 这类「看不见但有空白语义」的字符,见 空白与换行

5 · 参考文献

  1. Unicode. FAQ: Private-Use Characters, Noncharacters & Sentinels. 私用区与非字符的用途、为什么标准保证永不分配。unicode.org
  2. Boucher, N. & Anderson, R. Trojan Source(CVE-2021-42574). bidi 控制符怎么让源码「看的和编译的不一样」。trojansource.codes
  3. Unicode. Full Emoji List. 逐码点查证各平台对国旗等序列的真实渲染。unicode.org