52

好的。我知道这看起来像是典型的“他为什么不直接谷歌搜索或访问www.unicode.org并查找它?” 问题,但是对于这样一个简单的问题,在检查了两个来源后,我仍然无法找到答案。

我很确定所有这三种编码系统都支持所有的 Unicode 字符,但在我在演示文稿中提出该声明之前,我需要确认它。

额外问题:这些编码在可以扩展支持的字符数上是否不同?

4

6 回答 6

66

没有 Unicode 字符可以存储在一种编码中,但不能存储在另一种编码中。这仅仅是因为有效的 Unicode 字符被限制为可以存储在 UTF-16 中的内容(它具有三种编码中最小的容量)。换句话说,UTF-8 和 UTF-32可以用来表示比 UTF-16 更广泛的字符,但它们不是. 请阅读以获得更多详情。

UTF-8

UTF-8 是可变长度代码。有些字符需要 1 个字节,有些需要 2 个字节,有些需要 3 个字节,有些需要 4 个字节。每个字符的字节只是一个接一个地写入连续的字节流。

虽然一些 UTF-8 字符可以是 4 个字节长,但 UTF-8不能编码 2^32 个字符。它甚至不接近。我将尝试解释其中的原因。

读取 UTF-8 流的软件只获取一个字节序列 - 它应该如何确定接下来的 4 个字节是单个 4 字节字符,还是两个 2 字节字符,还是四个 1 字节字符(或其他组合)?基本上,这是通过确定某些 1 字节序列不是有效字符、某些 2 字节序列不是有效字符等等来完成的。当这些无效序列出现时,假定它们构成较长序列的一部分。

你已经看到了一个相当不同的例子,我敢肯定:它被称为转义。在许多编程语言中,\字符串源代码中的字符不会转换为字符串“编译”形式中的任何有效字符。当在源中找到 \ 时,假定它是较长序列的一部分,例如\nor \xFF。请注意,这\x是一个无效的 2 字符序列,\xF也是一个无效的 3 字符序列,但\xFF它是一个有效的 4 字符序列。

基本上,在拥有许多字符和拥有更短的字符之间需要权衡取舍。如果你想要 2^32 个字符,它们平均需要 4 个字节长。如果您希望所有字符为 2 个字节或更少,那么您不能超过 2^16 个字符。UTF-8 提供了一个合理的折衷方案:所有ASCII字符(ASCII 0 到 127)都被赋予 1 字节表示,这对兼容性非常有利,但允许使用更多字符。

像大多数可变长度编码一样,包括上面显示的各种转义序列,UTF-8 是一种瞬时编码。这意味着,解码器只是逐字节读取,并且一旦到达字符的最后一个字节,它就知道该字符是什么(并且它知道它不是更长字符的开头)。

例如,字符“A”使用字节 65 表示,并且没有第一个字节为 65 的二/三/四字节字符。否则解码器将无法将这些字符与“A”区分开来' 其次是别的东西。

但是 UTF-8 受到了更进一步的限制。它确保较短字符的编码永远不会出现较长字符的编码中。例如,一个 4 字节字符中的任何一个字节都不能是 65。

由于 UTF-8 有 128 个不同的 1 字节字符(其字节值为 0-127),所有 2、3 和 4 字节字符必须仅由 128-256 范围内的字节组成。这是一个很大的限制。但是,它允许面向字节的字符串函数在很少或不需要修改的情况下工作。例如,strstr()如果 C 的输入是有效的 UTF-8 字符串,则 C 的函数总是按预期工作。

UTF-16

UTF-16 也是变长编码;它的字符消耗 2 或 4 个字节。0xD800-0xDFFF 范围内的 2 字节值保留用于构造 4 字节字符,所有 4 字节字符由 0xD800-0xDBFF 范围内的两个字节和 0xDC00-0xDFFF 范围内的 2 个字节组成。因此,Unicode 不会分配 U+D800-U+DFFF 范围内的任何字符。

UTF-32

UTF-32 是一个固定长度的编码,每个字符有 4 个字节长。虽然这允许对 2^32 个不同字符进行编码,但在此方案中只允许 0 到 0x10FFFF 之间的值。

容量比较:

  • UTF-8: 2,097,152(实际上是 2,166,912,但由于设计细节,其中一些映射到同一事物)
  • UTF-16: 1,112,064
  • UTF-32: 4,294,967,296(但仅限于前 1,114,112)

因此,最受限制的是 UTF-16!正式的 Unicode 定义将 Unicode 字符限制为可以用 UTF-16 编码的字符(即范围 U+0000 到 U+10FFFF,不包括 U+D800 到 U+DFFF)。UTF-8 和 UTF-32 支持所有这些字符。

UTF-8 系统实际上“人为地”限制为 4 个字节。它可以扩展到 8 个字节而不违反我之前概述的限制,这将产生 2^42 的容量。最初的 UTF-8 规范实际上最多允许 6 个字节,即 2^31 的容量。但是RFC 3629将其限制为 4 个字节,因为这是涵盖 UTF-16 的所有功能所需的字节数。

还有其他(主要是历史性的)Unicode 编码方案,特别是 UCS-2(它只能将 U+0000 编码为 U+FFFF)。

于 2008-11-11T06:42:25.853 回答
45

不,它们只是不同的编码方法。它们都支持对同一组字符进行编码。

UTF-8 每个字符使用 1 到 4 个字节,具体取决于您要编码的字符。ASCII 范围内的字符只占用一个字节,而非常不寻常的字符占用四个字节。

UTF-32 无论是什么字符,每个字符都使用四个字节,因此它总是比 UTF-8 使用更多的空间来编码相同的字符串。唯一的好处是您可以仅通过计算字节数来计算 UTF-32 字符串中的字符数。

UTF-16 对大多数字符使用两个字节,对不寻常的字符使用四个字节。

http://en.wikipedia.org/wiki/Comparison_of_Unicode_encodings

于 2008-09-24T23:04:26.293 回答
7

UTF-8、UTF-16 和 UTF-32 都支持完整的 unicode 代码点集。没有一个字符支持但另一个字符不支持。

至于额外的问题“这些编码在它们可以扩展支持的字符数量上是否不同?” 是和不是。UTF-8 和 UTF-16 的编码方式将它们可以支持的代码点总数限制在 2^32 以下。但是,Unicode 联盟不会将无法以 UTF-8 或 UTF-16 表示的代码点添加到 UTF-32。这样做会违反编码标准的精神,并且无法保证从 UTF-32 到 UTF-8(或 UTF-16)的一对一映射。

于 2008-09-24T23:00:06.600 回答
5

如果有疑问,我个人总是会查看Joel 关于 unicode、编码和字符集的帖子。

于 2008-09-24T22:55:47.407 回答
4

所有 UTF-8/16/32 编码都可以映射所有 Unicode 字符。请参阅Wikipedia 的 Unicode 编码比较

这篇 IBM 文章Encode your XML documents in UTF-8非常有帮助,并指出如果您可以选择,最好选择 UTF-8。主要原因是广泛的工具支持,UTF-8通常可以通过不知道 unicode 的系统。

IBM 文章的规格说明部分:

W3C 和 IETF 最近都更加坚定地首先选择 UTF-8,最后选择,有时甚至只选择 UTF-8。The W3C Character Model for the World Wide Web 1.0: Fundamentals 指出,“当需要唯一的字符编码时,字符编码必须是 UTF-8、UTF-16 或 UTF-32。US-ASCII 向上兼容 UTF- 8(US-ASCII 字符串也是 UTF-8 字符串,参见 [RFC 3629]),因此如果需要与 US-ASCII 兼容,则 UTF-8 是合适的。” 在实践中,与 US-ASCII 的兼容性非常有用,几乎是一项要求。W3C 明智地解释说,“在其他情况下,例如对于 API,UTF-16 或 UTF-32 可能更合适。选择其中之一的可能原因包括内部处理的效率和与其他进程的互操作性。”

于 2008-09-24T23:13:35.820 回答
2

正如大家所说,UTF-8、UTF-16 和 UTF-32 都可以编码所有的 Unicode 码位。但是,UCS-2(有时被错误地称为 UCS-16)变体不能,这就是您可以在例如 Windows XP/Vista 中找到的变体。

有关更多信息,请参阅维基百科

编辑:我对 Windows 的看法是错误的,NT 是唯一支持 UCS-2 的。但是,许多 Windows 应用程序会像 UCS-2 中一样假定每个代码点只有一个单词,因此您很可能会发现错误。请参阅另一篇维基百科文章。(感谢杰森真)

于 2008-09-25T02:18:25.627 回答