UTF-8,UTF-16和UTF-32

时间:2009-01-30 17:06:00

标签: unicode utf-8 utf-16 utf utf-32

UTF-8,UTF-16和UTF-32之间有什么区别?

我知道它们都将存储Unicode,并且每个都使用不同的字节数来表示字符。选择一个优于另一个是否有优势?

13 个答案:

答案 0 :(得分:327)

UTF-8在ASCII字符代表文本块中的大多数字符的情况下具有优势,因为UTF-8将所有字符编码为8位(如ASCII)。还有一个优点是,仅包含ASCII字符的UTF-8文件具有与ASCII文件相同的编码。

UTF-16在ASCII不占优势的地方更好,因为它主要使用每个字符2个字节。对于高阶字符,UTF-8将开始使用3个或更多字节,对于大多数字符,UTF-16仅保留2个字节。

UTF-32将覆盖4个字节中的所有可能字符。这让它变得非常臃肿。我想不出使用它有什么好处。

答案 1 :(得分:290)

简而言之:

  • UTF-8:可变宽度编码,向后兼容ASCII。 ASCII字符(U + 0000到U + 007F)取1个字节,代码点U + 0080到U + 07FF取2个字节,代码点U + 0800到U + FFFF取3个字节,代码点U + 10000到U + 10FFFF需要4个字节。适用于英文文本,对亚洲文本不太好。
  • UTF-16:可变宽度编码。代码点U + 0000到U + FFFF需要2个字节,代码点U + 10000到U + 10FFFF需要4个字节。不适合英文文本,适合亚洲文字。
  • UTF-32:固定宽度编码。所有代码点都占用四个字节。巨大的记忆力,但快速操作。很少使用。

长期:请参阅维基百科:UTF-8UTF-16UTF-32

答案 2 :(得分:108)

  • UTF-8可变 1到4 字节。

  • UTF-16是可变的 2或4 字节。

  • UTF-32固定 4 字节。

答案 3 :(得分:73)

Unicode定义了一个巨大的字符集,为每个图形符号分配一个唯一的整数值(这是一个主要的简化,实际上并不是真的,但它足够接近这个问题的目的)。 UTF-8/16/32只是不同的编码方式。

简而言之,UTF-32为每个字符使用32位值。这允许他们为每个角色使用固定宽度的代码。

UTF-16默认使用16位,但这只能为您提供65k个可能的字符,这对于完整的Unicode集来说已经足够了。所以有些字符使用16位值对。

UTF-8默认使用8位值,这意味着127个第一个值是固定宽度的单字节字符(最高有效位用于表示这是多字节序列的开头) ,为实际字符值留下7位)。所有其他字符编码为最多4个字节的序列(如果内存服务)。

这使我们获益。任何ASCII字符都与UTF-8直接兼容,因此对于升级旧版应用程序,UTF-8是一种常见且明显的选择。在几乎所有情况下,它也将使用最少的内存。另一方面,您无法保证角色的宽度。它可能是1,2,3或4个字符宽,这使得字符串操作变得困难。

UTF-32相反,它使用最多的内存(每个字符是一个固定的4字节宽),但另一方面,你知道每个字符都有这个精确的长度,所以字符串操纵变得简单得多。您可以根据字符串的字节长度计算字符串中的字符数。你不能用UTF-8做到这一点。

UTF-16是一种妥协。它允许大多数字符符合固定宽度的16位值。因此,只要您没有中文符号,音符或其他符号,就可以假设每个字符都是16位宽。它使用的内存比UTF-32少。但它在某种程度上是“两个世界中最糟糕的”。它几乎总是使用比UTF-8更多的内存,它仍然无法避免困扰UTF-8(可变长度字符)的问题。

最后,了解平台支持的内容通常很有帮助。 Windows在内部使用UTF-16,因此在Windows上,这是显而易见的选择。

Linux有所不同,但它们通常使用UTF-8来处理符合Unicode的所有内容。

如此简短的回答:所有三种编码都可以编码相同的字符集,但它们将每个字符表示为不同的字节序列。

答案 4 :(得分:40)

Unicode 是一个标准,关于 UTF-x 您可以将其视为某些实际用途的技术实现:

  • UTF-8 - “尺寸优化”:最适合基于拉丁字符的数据(或ASCII),每个字符只需1个字节但尺寸相应增大符号种类(在最坏的情况下,每个字符最多可增长6个字节)
  • UTF-16 - “余额”:每个字符至少需要2个字节,足以支持现有的主流语言集,并且具有固定的大小字符处理(但大小仍然是可变的,每个字符最多可增长4个字节)
  • UTF-32 - “性能”:允许使用简单算法作为固定大小字符(4个字节)的结果,但内存不足

答案 5 :(得分:20)

我试图在blogpost中给出一个简单的解释。

UTF-32

需要32位(4个字节)来编码任何字符。例如,为了使用此方案表示“A”字符代码点,您需要以32位二进制数写入65:

00000000 00000000 00000000 01000001 (Big Endian)

如果你仔细看一下,你会发现使用ASCII方案时,最右边的7位实际上是相同的位。但由于UTF-32是固定宽度方案,我们必须附加三个额外的字节。这意味着如果我们有两个只包含“A”字符的文件,一个是ASCII编码的,另一个是UTF-32编码的,它们的大小相应地是1个字节和4个字节。

UTF-16

许多人认为,由于UTF-32使用固定宽度32位来表示代码点,因此UTF-16的固定宽度为16位。错误!

在UTF-16中,代码点可以用16位或32位表示。所以这个方案是可变长度编码系统。与UTF-32相比有什么优势?至少对于ASCII,文件的大小不会是原始文件的4倍(但仍然是两倍),所以我们仍然不能向后兼容ASCII。

由于7位足以表示“A”字符,因此我们现在可以使用2个字节而不是像UTF-32那样的4个字节。它看起来像是:

00000000 01000001

UTF-8

你猜对了..在UTF-8中,代码点可以用32,16,24或8位表示,而作为UTF-16系统,这个也是可变长度编码系统。

最后,我们可以用与ASCII编码系统相同的方式表示“A”:

01001101

一个小例子,其中UTF-16实际上优于UTF-8:

考虑中文字母“语” - 其UTF-8编码为:

11101000 10101010 10011110

虽然其UTF-16编码较短:

10001010 10011110

为了理解表示及其解释方式,请访问原始帖子。

答案 6 :(得分:18)

UTF-8

  • 没有字节顺序的概念
  • 每个字符使用1到4个字节
  • ASCII是编码的兼容子集
  • 完全自我同步,例如从流中的任何位置删除的字节最多会损坏一个字符
  • 几乎所有欧洲语言都以两个字节或更少的字符编码

UTF-16

  • 必须使用已知的字节顺序进行解析或读取字节顺序标记(BOM)
  • 每个字符使用2或4个字节

UTF-32

  • 每个字符都是4个字节
  • 必须使用已知的字节顺序进行解析或读取字节顺序标记(BOM)
除非大部分字符来自CJK(中文,日文和韩文)字符空间,否则UTF-8将是最节省空间的。

UTF-32最适合通过字符偏移随机访问字节数组。

答案 7 :(得分:13)

我做了一些测试来比较MySQL中UTF-8和UTF-16之间的数据库性能。

更新速度

UTF-8

Enter image description here

UTF-16

Enter image description here

插入速度

Enter image description here

Enter image description here

删除速度

Enter image description here

Enter image description here

答案 8 :(得分:11)

在UTF-32中,所有字符都用32位编码。优点是您可以轻松计算字符串的长度。缺点是对于每个ASCII字符,你会浪费额外的三个字节。

在UTF-8字符中有可变长度,ASCII字符以一个字节(8位)编码,大多数西方特殊字符以两个字节或三个字节(例如€是三个字节)编码,并且更具异国情调的字符最多可以占用四个字节。明显的缺点是,先验你无法计算字符串的长度。但与UTF-32相比,编码拉丁(英语)字母文本所需的字节数要少得多。

UTF-16也是可变长度。字符以两个字节或四个字节编码。我真的没有看到这一点。它具有可变长度的缺点,但没有像UTF-8那样节省空间的优点。

在这三者中,显然UTF-8的传播范围最广。

答案 9 :(得分:6)

根据您的开发环境,您甚至可能无法选择字符串数据类型在内部使用的编码。

但是对于存储和交换数据,我总是使用UTF-8,如果你有选择的话。如果您主要拥有ASCII数据,这将为您提供最少量的数据传输,同时仍然可以对所有内容进行编码。优化最少的I / O是现代机器的发展方向。

答案 10 :(得分:4)

我很惊讶这个问题已经有 11 年历史了,而且没有一个答案提到 utf-8 的 #1 优势。

utf-8 通常适用于不支持 utf-8 的程序。这部分是它的设计目的。其他答案提到前 128 个代码点与 ASCII 相同。所有其他代码点都是由 8 位值和高位集(值从 128 到 255)生成的,因此从非 Unicode 感知程序的 POV 来看,它只会将字符串视为带有一些额外字符的 ASCII。

举个例子,假设你编写了一个程序来添加行号,可以有效地做到这一点(为了简单起见,我们假设行尾只是 ASCII 13)

// pseudo code

function readLine
  if end of file
     return null
  read bytes (8bit values) into string until you hit 13 or end or file
  return string

function main
  lineNo = 1
  do {
    s = readLine
    if (s == null) break;
    print lineNo++, s
  }  

将 utf-8 文件传递​​给该程序将继续工作。类似地,拆分制表符、逗号、解析 ASCII 引号或其他只有 ASCII 值有意义的解析都只适用于 utf-8,因为 utf-8 中没有出现 ASCII 值,除非它们实际上是那些 ASCII 值

其他一些答案或评论提到 utf-32 的优点是您可以单独处理每个代码点。例如,这建议您可以采用像“ABCDEFGHI”这样的字符串,并在每个第三个代码点处将其拆分为

ABC
DEF
GHI

这是错误的。 Many code points affect other code points。例如颜色选择器代码点,它可以让你在??‍???‍???‍???‍???‍?之间进行选择。如果您在任意代码点处拆分,则会破坏它们。

另一个例子是双向代码点。以下段落输入后退。它前面只是 0x202E 代码点

<块引用>
  • 此行不向后输入,只向后显示

所以不,utf-32 不会让你随意操作 unicode 字符串而不考虑它们的含义。它将让您无需额外代码即可查看每个代码点。

仅供参考,utf-8 旨在让您查看任何单个字节都可以找到当前代码点或下一个代码点的开头。

如果您在 utf-8 数据中取任意字节。如果它 < 128,它本身就是正确的代码点。如果 >= 128 和 < 192(前 2 位是 10),那么要找到代码点的开始,您需要查看前一个字节,直到找到一个值 >= 192 的字节(前 2 位是 11 )。在该字节处,您找到了代码点的开头。该字节编码了有多少后续字节构成代码点。

如果您想找到下一个代码点,只需扫描直到字节 < 128 或 >= 192 为止,这就是下一个代码点的开始。

<头>
字节数 第一个代码点 最后一个代码点 字节 1 字节 2 字节 3 字节 4
1 U+0000 U+007F 0xxxxxxx
2 U+0080 U+07FF 110xxxxx 10xxxxxx
3 U+0800 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
4 U+10000 U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

其中 xxxxxx 是代码点的位。连接字节中的 xxxx 位以获得代码点

答案 11 :(得分:2)

如上所述,差异主要是底层变量的大小,在每种情况下变量都会变大,以允许表示更多的字符。

但是,字体,编码和事情都很复杂(不必要?),因此需要一个很大的链接来填写更多细节:

http://www.cs.tut.fi/~jkorpela/chars.html#ascii

不要指望理解这一切,但如果你不想在以后遇到问题,尽可能多地学习,尽可能早(或者只是让其他人为你解决) 。

保罗。

答案 12 :(得分:-1)

简而言之,使用UTF-16或UTF-32的唯一理由是分别支持非英语和古代脚本。

我想知道为什么有人会选择使用非UTF-8编码,因为它显然更有效地用于网络/编程。

常见的误解 - 后缀数字并不表示其能力。它们都支持完整的Unicode,只是UTF-8可以用单个字节处理ASCII,因此对CPU和互联网来说效率更高/更不易损坏。

一些好的阅读:http://www.personal.psu.edu/ejp10/blogs/gotunicode/2007/10/which_utf_do_i_use.htmlhttp://utf8everywhere.org