UTF-8,UTF-16和UTF-32


486

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

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


36
如果您对Unicode的工作方式感兴趣,请观看此视频youtube.com/watch?v=MijmeoH9LT4

1
该视频聚焦于UTF-8,是的,它很好地解释了可变长度编码的工作原理,并且与仅读取或写入固定长度ASCII的计算机基本兼容。Unicode家伙在设计UTF-8编码时很聪明。
2014年

1
我已经创建了一个在线工具来进行转换和比较。
阿米特·库玛·古普塔

1
UTF-8是大多数用于保存文件的现代软件中的事实上的标准。更具体地说,它是用于HTML以及配置和翻译文件的最广泛使用的编码(例如,Minecraft对其所有文本信息不接受任何其他编码)。UTF-32 用于内部内存表示的速度很快,而UTF-16已被弃用,出于历史原因,当前仅在Win32中使用(当Windows 95是事物时,UTF-16是固定长度的)
Kotauskas

@VladislavToncharov UTF-16从来不是固定长度的编码。您将其与UCS-2混淆了。

Answers:


373

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

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

UTF-32将覆盖4个字节中的所有可能字符。这使它显得肿。我想不出使用它的任何优势。


165
UTF-32的优点:您不需要将存储的数据解码到32位Unicode代码点,例如逐字符处理。代码点已经可以在数组/向量/字符串中找到。
richq

22
如果(必须帮助您)重新实现轮子,也更容易解析。
Paul McMillan

24
好吧,UTF-8在网络传输中有一个优势-无需担心字节顺序,因为您一次只传输一个字节(而不是4个字节)。
2011年

30
@richq您不能在UTF-32中进行逐字符处理,因为代码点并不总是与字符相对应。
hamstergene

4
UTF-32的优势:与utf-8等效的字符串操作相比,字符串处理可能更快
Wes

331

简而言之:

  • 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:固定宽度编码。所有代码点占用四个字节。巨大的内存消耗,但是操作起来很快。很少使用。

详细地说:请参阅Wikipedia:UTF-8UTF-16UTF-32


65
@spurrymoses:我指的是数据字节占用的空间量。每个亚洲字符UTF-8需要3个字节,而每个亚洲字符UTF-16只需要2个字节。这确实不是一个主要问题,因为与程序存储器中存储的平均文本数量相比,如今计算机拥有大量的存储器。
亚当·罗森菲尔德2009年

12
UTF-32不再很少使用了……在osx和linux上wchar_t默认为4字节。gcc有一个选项-fshort-wchar,可以将大小减小到2个字节,但是破坏了与std libs的二进制兼容性。
vine'th 2011年

9
@PandaWood ofcource UTF-8可以编码任何字符!但是,您是否将内存需求与UTF-16的需求进行了比较?您似乎错过了重点!
Ustaman Sangat 2011年

16
如果有人说在所有编码格式(包括那些无法对Unicode进行编码的格式)的上下文中,UTF-8都不适合“亚洲文字”,那么它们当然是错误的。但这不是上下文。内存需求的上下文来自以下事实:问题(和答案)正在比较UTF-8,UTF-16和UTF-32,它们都将对亚洲文本进行编码,但使用不同的内存/存储量。随之而来的是,它们的相对优度自然将完全取决于内存需求。“不太好”!=“不好”。
Paul Gregory

5
@McGafter:当然有。如果您想获得信任,请直接去Unicode联盟。有关UTF- *编码的说明,请参见第2.5章。但是,为了获得对编码的简单,高层次的理解,我发现Wikipedia文章是更容易上手的资料。
亚当·罗森菲尔德

116
  • UTF-8是1到4个字节的变量。

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

  • UTF-32是固定的4个字节。

注意:UTF-8可以采用最新约定的1到6个字节:https : //lists.gnu.org/archive/html/help-flex/2005-01/msg00030.html


35
UTF8实际上是1到6个字节。
Urkle

6
@Urkle在技术上是正确的,因为映射整个UTF32 / LE / BE都包括U-00200000-U-7FFFFFFF,即使Unicode v6.3以U-0010FFFF结尾。这是有关如何对5个字节和6个字节的utf8进行编码的详细

4
用相关的参考零件及其来源备份这些?
n611x007 2014年

20
@Urkle不,UTF-8不能为5或6个字节。Unicode代码点限制为21位,这将UTF-8限制为4个字节。(您当然可以扩展UTF-8的原理来编码任意大整数,但它不是Unicode。)请参阅RFC3629。–
rdb

11
引用维基百科:2003年11月,RFC 3629对UTF-8进行了限制,以匹配UTF-16字符编码的约束条件:明确禁止与高和低代理字符相对应的代码点删除了三字节序列中的3%以上,并以U + 10FFFF结尾,删除了48%以上的四字节序列以及所有五字节和六字节序列。
亚当·卡维特·布尔

79

Unicode定义了一个巨大的字符集,为每个图形符号分配了一个唯一的整数值(这是一个重大的简化,实际上并不正确,但是对于这个问题而言,它已经足够接近了)。UTF-8 / 16/32是对此进行编码的不同方法。

简而言之,UTF-32为每个字符使用32位值。这样一来,他们就可以为每个字符使用固定宽度的代码。

UTF-16默认情况下使用16位,但这只能为您提供65,000个可能的字符,对于完整的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略有不同,但是对于兼容Unicode的所有内容,它们通常都使用UTF-8。

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


12
说Unicode为每个图形符号分配一个唯一的整数是不正确的。它为每个代码点分配了此类代码,但是某些代码点是不可见的控制字符,并且某些图形符号需要多个代码点来表示。
tchrist 2012年

15
@tchrist:是的,这是不准确的。问题是要准确解释Unicode,您需要编写数千页。我希望了解基本概念以解释编码之间的区别
jalf 2012年

@jalf大声笑对,基本上可以解释Unicode了,您必须编写Unicode核心规范
Justin Ohms

@tchrist更具体地说,您可以从提供的基元中构造中文符号(但是它们在同一张图表中,因此您最终将使用不真实的空间(磁盘或RAM)对它们进行编码),而不是使用内置的。
Kotauskas

44

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

  • UTF-8-大小优化 ”:最适合基于拉丁字符的数据(或ASCII),每个字符仅占用1个字节,但是大小相应地增加了符号种类(在最坏的情况下,每个字符最多可以增加6个字节)
  • UTF-16-平衡 ”:每个字符最少占用2个字节,这对于现有的主流语言集已足够,具有固定的大小以简化字符处理(但大小仍然可变,每个字符最多可以增加4个字节) )
  • UTF-32-性能 ”:由于使用固定大小的字符(4个字节)而允许使用简单算法,但存在内存不足的问题

«主流语言»在世界很多地方不是主流^^
tuxayo

2
UTF-16实际上针对非ASCII字符进行了大小优化。因为它实际上取决于将使用哪种语言。
tuxayo

@tuxayo完全同意,值得注意的是世界亚洲部分的汉字和汉字字符集。
菜鸟

应该是最佳答案。这太正确了,不能埋在这里。
MichalŠtein

28

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

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

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


19

UTF-8

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

UTF-16

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

UTF-32

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

除非大多数字符都来自CJK(中文,日文和韩文)字符空间,否则UTF-8将是最节省空间的。

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


UTF-8中的“自我同步”如何工作?您可以举1个字节和2个字节字符的示例吗?
Koray Tugay

2
@KorayTugay有效的较短字节字符串永远不会用在较长字符中。例如,ASCII的范围是0-127,这意味着所有一字节字符都采用0xxxxxxx二进制形式。所有两个字节的字符都110xxxxx以第二个字节开始10xxxxxx。因此,假设两个字节字符的第一个字符丢失了。一看到10xxxxxx没有110xxxxxx前置字符,您就可以确定一个字节是否丢失或损坏,并丢弃该字符(或从服务器或其他设备重新请求该字符),然后继续操作,直到再次看到一个有效的第一个字节。
克里斯(Chris)

1
如果您有字符的偏移量,则有该字符的偏移量– utf8,utf16或utf32在这种情况下将完全相同;也就是说,它们在通过字符偏移到字节数组中的随机访问方面都同样出色。utf32比utf8更能计数字符的想法也是完全错误的。甲码点(这是一样的字符再次,是不一样的一个字形..叹息),是32个比特宽在UTF32和8和32之间的位UTF8,但一个字符可以跨越多个码点,其破坏了人们声称utf32优于utf8的主要优势。
清晰的时间是


14

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

在具有可变长度的UTF-8字符中,ASCII字符被编码为一个字节(八位),大多数西方特殊字符被编码为两个字节或三个字节(例如€为三个字节),并且更多的特殊字符可能会被占用到四个字节。明显的缺点是,先验不能计算字符串的长度。但是,与UTF-32相比,对拉丁(英语)字母文本进行编码所需的字节要少得多。

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

在这三者中,显然UTF-8是使用最广泛的。


为什么在开发网站时我要计算字符串的长度?在Web开发中选择UTF-8 / UTF-16有什么优势?
Morfidon

“优点是您可以轻松地计算字符串的长度”如果用代码点数定义长度,那么可以,只需将字节长度除以4,即可使用UTF-32获得它。但是,这不是一个非常有用的定义:它可能与字符数无关。同样,规范化可能会更改字符串中代码点的数量。例如,法语单词“été”可以用至少3种不同的代码点长度以至少4种不同的方式进行编码。

UTF-16可能比UTF-8快,同时也没有像UTF-32那样浪费内存。
MichalŠtein

6

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

但是对于存储和交换数据,如果可以选择的话,我将始终使用UTF-8。如果您大部分都是ASCII数据,那么这将为您提供最少的数据传输量,同时仍然能够对所有内容进行编码。针对最少的I / O进行优化是在现代计算机上运行的方法。


可以说,UTF-8不受字节顺序的影响,这比空间要求更为重要。UTF-16和UTF-32将不可避免地要处理字节序问题,而UTF-8只是字节流。
IInspectable '18

2

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

但是,字体,编码和事物非常复杂(不必要吗?),因此需要一个大链接来填充更多细节:

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

不要指望全部理解,但是如果您以后不想遇到问题,则值得尽早学习(或只是让别人为您解决问题),尽可能多地学习。

保罗


或仅使用UTF-8作为默认设置,因为它已成为事实上的标准,并确定新系统是否支持它。如果没有,您可以回到这篇文章。
robotik

-2

简而言之,使用UTF-16或UTF-32的唯一原因是分别支持非英语和古代文字。

我想知道为什么有人会选择非UTF-8编码,因为它明显更有效地用于Web /编程目的。

一个常见的误解-带后缀的数字并不表示其功能。它们都支持完整的Unicode,只是UTF-8可以处理单个字节的ASCII,所以效率更高/对CPU和Internet的破坏更小。

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


我不确定,为什么您建议使用UTF-16或UTF-32支持非英语文本。UTF-8可以很好地解决这一问题。英文文本中也有非ASCII字符。就像零宽度的非连接符。或一个破折号。恐怕,这个答案不会带来太多价值。
IInspectable

这个问题容易被否决,因为即使大多数字符都是UTF-8中的3字节字符,HTML文件中仍然普遍使用UTF-8,
23

@IInspectable支持不是最好的措辞,提升或更好的支持会更准确
robotik

发送类似utf8everywhere.org的页面不是我在SO答案中所要做的。
MichalŠtein
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.