【发布时间】:2010-09-12 22:14:02
【问题描述】:
好的。我知道这看起来像典型的“他为什么不直接谷歌它或去www.unicode.org 并查找它?” 问题,但是对于这样一个简单的问题,我在检查后仍然无法找到答案两个来源。
我很确定所有这三种编码系统都支持所有的 Unicode 字符,但我需要先确认一下,然后才能在演示文稿中做出该声明。
额外问题:这些编码在可以扩展支持的字符数上是否不同?
【问题讨论】:
标签: unicode character-encoding utf
好的。我知道这看起来像典型的“他为什么不直接谷歌它或去www.unicode.org 并查找它?” 问题,但是对于这样一个简单的问题,我在检查后仍然无法找到答案两个来源。
我很确定所有这三种编码系统都支持所有的 Unicode 字符,但我需要先确认一下,然后才能在演示文稿中做出该声明。
额外问题:这些编码在可以扩展支持的字符数上是否不同?
【问题讨论】:
标签: unicode character-encoding utf
没有 Unicode 字符可以存储在一种编码中,但不能存储在另一种编码中。这仅仅是因为有效的 Unicode 字符被限制为可以存储在 UTF-16 中的内容(它具有三种编码中最小的容量)。换句话说,UTF-8 和 UTF-32 可以用于表示比 UTF-16 更广泛的字符,但它们不是。继续阅读以了解更多详情。
UTF-8 是可变长度代码。有些字符需要 1 个字节,有些需要 2 个字节,有些需要 3 个字节,有些需要 4 个字节。每个字符的字节只是一个接一个地写入连续的字节流。
虽然某些 UTF-8 字符可以是 4 个字节长,但 UTF-8 不能编码 2^32 个字符。它甚至不接近。我将尝试解释其中的原因。
读取 UTF-8 流的软件只获取一个字节序列 - 它应该如何确定接下来的 4 个字节是单个 4 字节字符,还是两个 2 字节字符,还是四个 1 字节字符(或其他组合)?基本上,这是通过确定某些 1 字节序列不是有效字符、某些 2 字节序列不是有效字符等等来完成的。当这些无效序列出现时,假定它们构成更长序列的一部分。
我敢肯定,您已经看到了一个完全不同的例子:它被称为转义。在许多编程语言中,字符串源代码中的\ 字符不会转换为字符串“编译”形式中的任何有效字符。当在源中找到 \ 时,假定它是较长序列的一部分,例如 \n 或 \xFF。请注意,\x 是无效的 2 字符序列,\xF 是无效的 3 字符序列,但 \xFF 是有效的 4 字符序列。
基本上,在拥有多个字符和拥有更短的字符之间需要权衡取舍。如果你想要 2^32 个字符,它们平均需要 4 个字节长。如果您希望所有字符为 2 个字节或更少,那么您不能超过 2^16 个字符。 UTF-8 提供了一个合理的折衷方案:所有ASCII 字符(ASCII 0 到 127)都被赋予 1 字节表示,这非常有利于兼容性,但允许使用更多字符。
与大多数可变长度编码(包括上面显示的各种转义序列)一样,UTF-8 是instantaneous code。这意味着,解码器只是逐字节读取,一旦到达字符的最后一个字节,它就知道该字符是什么(并且它知道它不是一个字符的开头更长的字符)。
例如,字符“A”使用字节 65 表示,并且没有第一个字节为 65 的二/三/四字节字符。否则解码器将无法区分这些字符'A' 后跟其他内容。
但 UTF-8 受到了更进一步的限制。它确保较短字符的编码永远不会出现在较长字符的编码中任何地方。例如,一个 4 字节字符中的任何一个字节都不能是 65。
由于 UTF-8 有 128 个不同的 1 字节字符(其字节值为 0-127),所有 2、3 和 4 字节字符必须仅由 128-256 范围内的字节组成。这是一个很大的限制。但是,它允许面向字节的字符串函数在很少或不需要修改的情况下工作。例如,如果 C 的 strstr() 函数的输入是有效的 UTF-8 字符串,则它总是按预期工作。
UTF-16 也是变长编码;它的字符消耗 2 或 4 个字节。 0xD800-0xDFFF 范围内的 2 字节值保留用于构造 4 字节字符,所有 4 字节字符由 0xD800-0xDBFF 范围内的两个字节和 0xDC00-0xDFFF 范围内的 2 个字节组成。因此,Unicode 不会分配 U+D800-U+DFFF 范围内的任何字符。
UTF-32 是一个固定长度的代码,每个字符有 4 个字节长。虽然这允许对 2^32 个不同的字符进行编码,但此方案中只允许 0 到 0x10FFFF 之间的值。
因此,最受限制的是 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)。
【讨论】:
所有 UTF-8/16/32 编码都可以映射所有 Unicode 字符。见Wikipedia's Comparison of Unicode Encodings。
这篇 IBM 文章 Encode your XML documents in UTF-8 非常有帮助,并指出如果您有选择,最好选择 UTF-8。主要原因是广泛的工具支持,UTF-8通常可以通过不知道 unicode 的系统。
来自IBM article 中的规格说明部分:
W3C 和 IETF 都有 最近变得更加坚定 首先选择 UTF-8,最后选择 UTF-8,然后 有时只是。 W3C 角色 万维网 1.0 模型: 基本原理说,“当一个独特的 字符编码是必需的, 字符编码必须是 UTF-8, UTF-16 或 UTF-32。 US-ASCII 是 向上兼容 UTF-8(一个 US-ASCII 字符串也是 UTF-8 字符串,参见 [RFC 3629]),而 UTF-8 是 因此如果兼容性合适 需要使用 US-ASCII。”在 练习,兼容 US-ASCII 非常有用,几乎是 要求。 W3C 明智地解释说, “在其他情况下,例如 API、UTF-16 或 UTF-32 可能更多 合适的。可能的原因 选择其中之一包括 内部处理的效率和 与其他的互操作性 进程。”
【讨论】:
正如大家所说,UTF-8、UTF-16 和 UTF-32 都可以编码所有 Unicode 码位。但是,UCS-2(有时被错误地称为 UCS-16)变体不能,这就是您可以找到的变体,例如在 Windows XP/Vista 中。
更多信息请参见Wikipedia。
编辑:我错了 Windows,NT 是唯一支持 UCS-2 的。但是,许多 Windows 应用程序会假设每个代码点只有一个单词,就像 UCS-2 中一样,因此您很可能会发现错误。见another Wikipedia article。 (感谢 JasonTrue)
【讨论】:
不,它们只是不同的编码方法。它们都支持编码相同的字符集。
UTF-8 每个字符使用 1 到 4 个字节,具体取决于您要编码的字符。 ASCII 范围内的字符只占用一个字节,而非常不寻常的字符占用四个。
UTF-32 对每个字符使用四个字节,无论它是什么字符,因此它总是使用比 UTF-8 更多的空间来编码相同的字符串。唯一的好处是你可以通过只计算字节数来计算 UTF-32 字符串中的字符数。
UTF-16 对大多数字符使用两个字节,对不寻常的字符使用四个字节。
http://en.wikipedia.org/wiki/Comparison_of_Unicode_encodings
【讨论】:
String.codePointCount, String.codePointAt, &ᶜ — 从不使用 String.length, String.charAt, &ᶜ。看看所有 Java 的默认值是 ꜰᴜʙᴀʀ 吗? ? 使用 ᴜᴛꜰ‑8 ‖ ᴜᴛꜰ‑32,或使用 ᴍᴀᴅ 处理 w/ᴜᴛꜰ‑16 的白话ᵗsyncracies。
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)的一对一映射。
【讨论】:
如果有疑问,我个人总是会检查 Joel's post 的有关 unicode、编码和字符集的信息。
【讨论】: