UTF-8,UTF-16和UTF-32

459 unicode utf-8 utf-16 utf utf-32

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

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

Ant*_*nes 348

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

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

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

  • UTF-32优势:您不需要将存储的数据解码为32位Unicode代码点,例如逐字符处理.代码点已经在您的数组/向量/字符串中可用. (156认同)
  • 声明*"UTF-8将所有字符编码为8位"*是**错**.它不会**将*"全部"*字符编码为8位.它使用可变长度编码,它是8位的倍数.所以字符可以采用8,16,24,最多32位! (63认同)
  • @richq您不能在UTF-32中进行逐字符处理,因为代码点并不总是与字符对应. (29认同)
  • 好吧,UTF-8在网络传输方面具有优势 - 不需要担心字节顺序,因为你一次传输一个字节的数据(而不是4). (21认同)
  • 如果(天堂帮助你)你必须重新实现轮子,也更容易解析. (18认同)
  • 效果也一样,但这不是随机访问。例如,仅知道字符串的长度(以代码点为单位)就需要完全遍历字节数组,而使用 utf-32 则只需 sizeof(codepoints) (3认同)
  • 另一种描述 UTF32 随机访问能力的方法是说字符串切片在 UTF32 中是 O(1),在 UTF8 中是 O(n),即使在最好的情况下。 (3认同)
  • UTF-32的优势:与utf-8等效相比,字符串操作可能更快 (2认同)
  • @TimČas谈论代码点,而不是字形.在offset中定位代码点是utf-8中非常密集的操作,因为它需要完全迭代,并且"跳转"为2> 4个字节,而utf-32具有实际的随机访问.子串操作因此更快.相反,如你所说,定位字形需要在两种编码中完全遍历,但在utf-32中将需要较少的跳转. (2认同)
  • 这句话有点令人困惑:"UTF-8将所有字符编码为8位". (2认同)
  • `utf-32` 不仅对于字符串操作更有效(它支持随机访问;说得够多了!),而且由于是固定大小的数组,它也更容易操作(我敢说你使用 `utf-8`在“C”中...) (2认同)
  • @étale-cohomology 在 UTF-32 中随机访问*“字符”*(Unicode 技术上称为“字素簇”)是一个神话。即使完全标准化的 UTF-32 也使用组合字符(考虑表情符号!)。就像我说的,你几乎不需要代码点随机访问。 (2认同)

Ada*_*eld 308

简而言之:

  • 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-8,UTF-16UTF-32.

  • @spurrymoses:我严格指的是数据字节占用的空间量.UTF-8每个亚洲字符需要3个字节,而UTF-16每个亚洲字符只需要2个字节.这确实不是一个主要问题,因为与计算机内存中存储的平均文本量相比,计算机现在拥有大量内存. (62认同)
  • "UTF8对亚洲文本不是那么好"怎么样?这是错误的.例如,UTF-8非常适合日本人.我运行一个日本网站,所有内容都以UTF8编码,一切正常.UTF-8可以编码任何Unicode字符. (14认同)
  • 如果有人说在包含那些不能编码Unicode的编码格式的上下文中,UTF-8"对亚洲文本不太好",那么它们当然是错误的.但这不是背景.内存需求的上下文来自这样一个事实:问题(和答案)是比较UTF-8,UTF-16和UTF-32,它们都将编码亚洲文本但使用不同数量的内存/存储.因此,它们的相对优点自然完全在记忆要求的背景下."不太好"!="不好". (14认同)
  • UTF-32不再使用了......在osx和linux`wchar_t`默认为4个字节.gcc有一个选项`-fshort-wchar`,它将大小减小到2个字节,但打破了与std libs的二进制兼容性. (12认同)
  • @UstamanSangat是的,如果这个答案仅限于内存要求,那么我就错过了这一点.然而,这一点从未在答案中提出(问题也不需要它).那么看起来,我错过了一个从未做过的观点,但是你甚至在没有它的情况下能够看到它.当有人说UTF-8"对亚洲文本不太好"时 - 并没有将其限制在内存要求的上下文中,那就错了. (10认同)
  • @PandaWood of source UTF-8可以编码任何角色!但是你有没有将内存需求与UTF-16的内存需求进行比较?你好像错过了这一点! (6认同)
  • @McGafter:当然有.如果您想要值得信赖,请直接前往[The Unicode Consortium](http://www.unicode.org/versions/Unicode6.3.0/)的马口.有关UTF-*编码的说明,请参见第2.5章.但是为了获得对编码的简单,高级的理解,我发现维基百科的文章是一个更容易接近的来源. (4认同)
  • UTF-16工作的原因是U + D800-U + DFFF留在代理对对的BMP中作为间隙.聪明. (3认同)
  • Wikipedia指出,在现实世界中,由于文本中仍使用空格或英文单词,即使使用非英文字符,UTF-8的尺寸仍比UTF-16小。 (3认同)
  • @PandaWood 网页包含大量不属于正文的 ASCII 字符,因此无论您使用哪种语言,UTF-8 都是一个不错的选择。 (2认同)
  • 尽管大多数亚洲字符的UTF-8占用3个字节,而UTF-16的占用为2个字节(一些常用的汉字最终出现在多语言平面中,在UTF-8和UTF-16中它们都占用4个字节),实际上并没有太大的区别,因为实际文档中经常混入大量ASCII字符。有关一个真实文档的并排大小比较,请参见http://utf8everywhere.org/#asian:UTF-8实际上花了* 50与UTF-16相比,用于编码日语HTML页面(日本的Wikipedia文章,日语)的字节数减少了%*。 (2认同)

Qua*_*noi 109

  • UTF-8可变1到4个字节.

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

  • UTF-32固定为4个字节.

  • UTF8实际上是1到6个字节. (30认同)
  • @Urkle不,UTF-8不能是5或6个字节.Unicode代码点限制为21位,将UTF-8限制为4个字节.(你当然可以扩展UTF-8的原则来编码任意大整数,但它不是Unicode.)参见RFC 3629. (16认同)
  • 引用维基百科:2003年11月,UTF-8受到RFC 3629的限制,以匹配UTF-16字符编码的约束:明确禁止对应于高和低代理字符的代码点,删除超过3%的三字节序列,以U + 10FFFF结束,删除了超过48%的四字节序列和所有五字节和六字节序列. (9认同)
  • @Urkle在技术上是正确的,因为映射全范围的UTF32/LE/BE包括U-00200000-U-7FFFFFFF,即使Unicode v6.3以U-0010FFFF(包括端点)结束.这里有一个很好的细分如何加/减5和6字节utf8:https://lists.gnu.org/archive/html/help-flex/2005-01/msg00030.html (4认同)
  • 用相关的参考零件及其来源备份这些? (3认同)
  • @AaronFranke:第一个字节最多可以定义 7 个连续字节,因此从技术上讲,每个序列最多可以扩展到 8 个字节(36 个有效载荷位 ~ 680 亿个代码点)。 (2认同)

jal*_*alf 75

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的所有内容.

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

  • @tchrist:是的,这是不准确的.问题是要准确地解释Unicode,你需要编写数千页.我希望得到基本概念来解释编码之间的区别 (15认同)
  • 说Unicode为每个**图形符号**分配一个唯一的整数是不准确的.它将这样分配给每个代码点,但是一些代码点是**不可见的控制字符**,而一些图形符号需要**多个代码点**来表示. (12认同)
  • 迄今为止最好的答案 (2认同)
  • 请注意,UTF-32 的描述不正确。每个字符不是 4 个字节宽。每个代码点为 4 个字节宽,某些字符可能需要多个代码点。计算字符串长度不仅仅是字节数除以 4,您还必须遍历整个字符串并解码每个代码点才能解析这些簇。 (2认同)

roo*_*ook 41

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

  • UTF-8 - " 大小优化 ":最适合基于拉丁字符的数据(或ASCII),每个字符只需1个字节,但大小相应增加符号种类(在最坏的情况下,每个字符最多可增加6个字节)
  • UTF-16 - " 平衡 ":每个字符至少需要2个字节,这对于现有的主流语言集来说已经足够了,它具有固定的大小以便于字符处理(但是大小仍然是可变的,并且每个字符可以增长到4个字节)
  • UTF-32 - " 性能 ":允许使用简单算法作为固定大小字符(4字节)的结果,但存在内存缺点

  • UTF-16 实际上是针对非 ASCII 字符进行大小优化的。因为这实际上取决于它将使用哪种语言。 (3认同)
  • utf-8 可能比所有这些都更快,因为开发人员花费了最多的精力来优化它 (3认同)

Mar*_*oun 23

我试着在我的博文中给出一个简单的解释.

UTF-32

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

00000000 00000000 00000000 01000001 (Big Endian)
Run Code Online (Sandbox Code Playgroud)

如果仔细观察一下,你会发现使用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
Run Code Online (Sandbox Code Playgroud)

UTF-8

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

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

01001101
Run Code Online (Sandbox Code Playgroud)

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

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

11101000 10101010 10011110
Run Code Online (Sandbox Code Playgroud)

虽然它的UTF-16编码更短:

10001010 10011110
Run Code Online (Sandbox Code Playgroud)

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


Jef*_*son 19

UTF-8

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

UTF-16

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

UTF-32

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

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

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

  • @KorayTugay有效的较短字节字符串从不用于较长的字符.例如,ASCII在0-127范围内,这意味着所有单字节字符都具有二进制形式的"0xxxxxxx".所有双字节字符以"110xxxxx"开头,第二个字节为"10xxxxxx".因此,假设两个字节字符的第一个字符丢失了.一旦你看到没有前面的'110xxxxxx`的`10xxxxxx`,你可以确定一个字节丢失或损坏,并丢弃该字符(或从服务器或其他任何地方重新请求它),然后继续前进直到你再看一个有效的第一个字节. (2认同)

var*_*tec 13

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

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

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

在这三个中,显然UTF-8是最广泛传播的.


Far*_*mov 13

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

更新速度

UTF-8

在此输入图像描述

UTF-16

在此输入图像描述

插入速度

在此输入图像描述

在此输入图像描述

删除速度

在此输入图像描述

在此输入图像描述

  • 一个短字符串并不能说明什么,一条记录就更少了,时间差异可能是其他因素造成的,Mysql本身的内部机制,如果要做可靠的测试,至少需要10000条记录一个200个字符的字符串,需要进行一组测试,有的场景,至少3个左右,所以会隔离编码因素 (3认同)

mgh*_*hie 6

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

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


sam*_*haj 5

我很惊讶这个问题已经有 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
  }  
Run Code Online (Sandbox Code Playgroud)

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

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

ABC
DEF
GHI
Run Code Online (Sandbox Code Playgroud)

这是错误的。许多代码点会影响其他代码点。例如,颜色选择器代码点可让您在 ????? 之间进行选择。如果您在任意代码点拆分,则会破坏它们。

另一个例子是双向代码点。以下段落没有倒着输入。它前面只是 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 位以获取代码点