4

我正在阅读一些关于 Unicode 的 SO 问题,其中有一些我不完全理解的评论,比如这个:

Dean Harding:UTF-8 是一种可变长度编码,处理起来比固定长度编码更复杂。另外,请参阅我对 Gumbo 回答的评论:基本上,所有编码(UTF-8、UTF-16 和 UTF-32)中都存在组合字符,它们需要特殊处理。您可以使用与组合字符相同的特殊处理方法来处理 UTF-16 中的代理项对,因此在大多数情况下,您可以忽略代理项并将 UTF-16 视为固定编码。

我对最后一部分(“大部分”)有点困惑。如果 UTF-16 被视为固定的 16 位编码,这会导致什么问题?BMP 之外有字符的可能性有多大?如果有,如果您假设使用两字节字符,这会导致什么问题?

我阅读了关于代孕的维基百科信息,但它并没有真正让我更清楚!

编辑:我想我真正的意思是“为什么有人建议将 UTF-16 视为固定编码,而它似乎是假的?”

编辑2:

我在“有什么理由比 UTF-8 更喜欢 UTF-16? ”中发现了另一条评论,我认为这更好地解释了这一点:

Andrew Russell:为了性能:UTF-8 比 UTF-16 更难解码。在 UTF-16 中,字符要么是基本多语言平面字符(2 个字节),要么是代理对(4 个字节)。UTF-8 字符可以是 1 到 4 个字节之间的任意位置

这表明要提出的观点是 UTF-16 不会有任何三字节字符,因此通过假设 16 位,您不会因为结束一个字节而“完全搞砸”。但我仍然不相信这与假设 UTF-8 是单字节字符有什么不同!

4

4 回答 4

3
于 2011-02-21T13:54:01.567 回答
3

重要的是要了解,即使 UTF-32 是固定长度的代码点,而不是字符。有许多字符是由多个代码点组成的,因此您不可能真正拥有一个数字(代码单元)对应一个字符(用户感知)的 Unicode 编码。

要回答您的问题 - 将 UTF-16 视为固定长度编码形式的最明显问题是在代理对中间断开一个字符串,这样您就会得到两个无效的代码点。这完全取决于您对文本的处理方式。

于 2011-02-21T14:06:57.540 回答
2

我想我真正的意思是“为什么有人建议将 UTF-16 视为固定编码,而它看起来是假的?”

两个字:向后兼容。

Unicode 最初旨在使用固定宽度的 16 位编码 (UCS-2),这就是为什么 Unicode 的早期采用者(例如,使用 Java 的 Sun 和使用 Windows NT 的 Microsoft)使用 16 位字符类型的原因。当事实证明 65,536 个字符对每个人来说都不够用时,开发了 UTF-16 是为了让这个 16 位字符系统能够代表 16 个新的“平面”。

这意味着字符不再是固定宽度的,因此人们创造了“没关系,因为 UTF-16几乎是固定宽度”的合理化解释。

但我仍然不相信这与假设 UTF-8 是单字节字符有什么不同!

严格来说,并没有什么不同。对于诸如"\uD801\uDC00".lower().

但是,假设 UTF-16 是固定宽度比假设 UTF-8 是固定宽度更不可能中断。非 ASCII 字符在英语以外的语言中非常常见,但非 BMP 字符非常少见。

您可以使用与组合字符相同的特殊处理来处理 UTF-16 中的代理对

我不知道他在说什么。组合序列,其组成字符具有个体身份,与代理字符完全不同,代理字符仅成对有意义。

特别地,组合序列中的字符可以一次转换为一个字符的不同编码。

>>> 'a'.encode('UTF-8') + '\u0301'.encode('UTF-8')
b'a\xcc\x81'

但不是代理:

>>> '\uD801'.encode('UTF-8') + '\uDC00'.encode('UTF-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'utf-8' codec can't encode character '\ud801' in position 0: surrogates not allowed
于 2011-02-22T13:56:29.080 回答
1

UTF-16 是一种可变长度编码。较旧的 UCS-2 不是。如果您将可变长度编码视为固定(恒定长度),那么每当您使用“16 位数字的数量”来表示“字符数”时,您就有可能引入错误,因为字符数实际上可能小于16 位数量。

于 2011-02-21T13:32:46.043 回答