本文介绍 .NET 使用的 character 编码系统。
本文中使用的术语“character”从读者的角度通常是指单个显示元素 。 常见的示例是字母“a”、“@”和表情符号 🐂
string 在逻辑上是一个 顺序 Char结构 的集合。Char 结构通过 UTF-16 编码来表示 Unicode 码位, 因此string.Length 属性返回 string 实例中 char 实例的数目。
每个 character 由一个 char 值表示。 这种模式适用于世界上大多数语言,但是,对于某些语言以及某些符号和表情符号,需要两个 char 实例来表示一个 character,映射到单个 character 的 char 对称为“代理项对”。因此string.Length并不一定是character的数量!
例如表情符号牛,由代理项对\ud83d和\udc02两个码位组成
"🐂".Length = 2
s[0] = '�' ('\ud83d')
s[1] = '�' ('\udc02')
Unicode 码位
Unicode字符集, 是一种国际编码标准,可用于各种平台以及各种语言和脚本。
Unicode 标准定义了超过 110 万个码位(1,114,112个)。 码位是一个整数值,范围从 0 到 U+10FFFF(十进制 1,114,111)。 一些码位被分配给字母、符号或表情符号。 其他码位分配给控制文本或 character 显示方式的操作,例如换行。 很多码位尚未经分配。
通常使用语法 U+xxxx 来表示码位,其中 xxxx 是十六进制编码的整数值。
整个码位范围包含两个子范围:
- U+0000..U+FFFF 范围内的基本多语言平面 (BMP)。 这个 16 位范围提供 65,536 个码位,足以涵盖世界上大多数编写系统。
- U+10000..U+10FFFF 范围内的补充码位。 这个 21 位范围提供了超过一百万个额外的码位,可用于不太知名的语言和其他用途,例如表情符号。
下图说明了 BMP 与补充码位之间的关系。
UTF-16
16 位 Unicode 转换格式 (UTF-16) 是一种 character 编码系统,它使用 16 位编码单元来表示一个 Unicode 码位。 .NET 使用 UTF-16 对 string 中的文本进行编码。 char 实例表示16 位编码单元。
单个 char 可以表示基本多语言平面(BMP)的 16 位范围内的任何码位。 但对于补充范围内的码位,需要两个 char 实例。
代理项对
BMP中有一段称为“代理项码位”的特殊范围,从 U+D800 到 U+DFFF,十进制 55,296 到 57,343,含限值,其中高代理项码位 (U+D800..U+DBFF)和低代理项码位 (U+DC00..U+DFFF),
这个范围单独一个码位无法表示一个character,需要通过高代理项码位 (U+D800..U+DBFF) 后紧跟低代理项码位 (U+DC00..U+DFFF)两个码位来表示一个character 。
通过此特殊范围,可以将两个 16 位值转换为一个 21 位值,因此使用代理机制,UTF-16 可以支持所有 1,114,112 个潜在的 Unicode 字符!!
通过使用以下公式,此代理项对将解释为补充码位:
code point = 0x10000 +
((high surrogate code point - 0xD800) * 0x0400) +
(low surrogate code point - 0xDC00)
下图说明了 BMP 与代理项码位之间的关系。
Unicode 标量值
术语“Unicode 标量值”是指除代理项码位之外的所有码位。
作为标量值的 Rune 类型
从 .NET Core 3.0 开始,System.Text.Rune 类型表示 Unicode 标量值。 Rune 在 .NET Core 2.x 或 .NET Framework 4.x 中不可用。
Rune a = new Rune('a');
Rune b = new Rune(0x0061);
Rune c = new Rune('\u0061');
Rune d = new Rune(0x10421);
Rune e = new Rune('\ud801', '\udc21');