C# 16位字符如何编码所有Unicode字符?

4

我了解到C#使用char (即System.Char)变量存储Unicode字符,这些变量的长度为16位。然而,16位无法存储所有Unicode字符!在这种情况下,C#的char变量如何支持Unicode呢?


1
https://en.wikipedia.org/wiki/UTF-16 - SLaks
Char 可以支持 U+0000 到 U+FFFF 范围内的任何 Unicode。 - maccettura
4
可能是使用大于2字节的Unicode字符与.Net的重复问题。 - maccettura
完全有效的问题。请阅读此答案,解释了这个问题。底线是,char最好是32位(而字符串相应地是32位值的序列),但正如我们在德国所说的,“那班火车已经开走了”。 - Peter - Reinstate Monica
可能是C#和UTF-16字符的重复问题。 - Tom Blodget
显示剩余3条评论
1个回答

6
简而言之:Surrogates
这是一个很好的问题。Unicode比大多数人想象中的要复杂,因为它引入了多个新概念(字符集、码点、编码、码元),但我会尽量给出一个几乎完整的答案。
简介:
Unicode是一个字符集。字符集只是由字符和代码点成对组成的列表。代码点只是用于标识配对字符的数字。UTF-8、UTF-16和UTF-32是编码。编码定义数字(代码点)如何以二进制形式表示(作为码元)。码元可以由一个或多个字节组成。(实际上,原始ASCII码元甚至只有7位长,但那是另一回事)
记住:字符集由代码点组成,编码由码元组成。
C# 的 char 类型表示一个 UTF-16 字符(码元)。UTF-16 是 Unicode 字符集的可变长度/多字节编码。这意味着字符可以由一个或两个 16 位码元表示。Unicode 码点超过 16 位则由两个 UTF-16 码元表示,等于四个字节。
现在来回答你的问题:怎么做?
Unicode 最初的想法是“1 个字符 = 1 个代码点”。但是最初的编码 UCS-2(现在已经过时)使用了两个字节(16 位),只能编码 65,536 个代码点。不久之后,这对于不断增长的 Unicode 字符集来说已经不够了。真的吗?两个字节显然是不够用的。为了解决这个问题,Unicode 必须放弃原始想法,并引入代理项。
因此,UTF-16 诞生了,它是一个可变长度/多字节(16 位码元)编码,实现了代理项。这些代理项是特殊的 16 位码元,等于 Unicode 中定义的代码点,明确不是字符。在解析文本时找到代理项只意味着您还必须读取接下来的 16 位,并将两个 16 位单元(代理项和随后的代码单元)解释为一个组合的 32 位 Unicode 代码点。
UTF-32 是一个固定的四字节编码,足够大以避免空间问题,并且可以将一个字符映射到一个代码点,但是 UTF-32 也必须处理代理项,因为 UTF 编码基于 Unicode 标准,而代理项是 Unicode 字符集定义的一部分。
UTF-8 也是一个可变长度/多字节编码,但具有另一种有趣的编码技术。简而言之:码元中前导零的数量定义了最多四个后续字节的数量,这些字节必须组合成一个 Unicode 代码点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接