什么是Unicode,UTF-8,UTF-16?

Sof*_*eek 368 unicode encoding utf-8 utf-16

什么是Unicode的基础以及为什么需要UTF-8或UTF-16?我在Google上研究了这个并在这里搜索过,但我不清楚.

在VSS进行文件比较时,有时会有消息说这两个文件有不同的UTF.为什么会这样呢?

请简单解释一下.

DPe*_*er1 516

为什么我们需要Unicode?

在(不太)早期,所有存在的都是ASCII.这是可以的,因为所需要的只是一些控制字符,标点符号,数字和字母,就像这句话中的那些.不幸的是,今天陌生的全球互通和社交媒体世界没有被预见到,在同一份文件中看到英语,العربية,汉语,ְְִִת,ελληνικά和is并不是太不寻常(我希望我没有打破任何旧的浏览器).

但是出于争论的缘故,让我们说Joe Average是一名软件开发人员.他坚持认为他只需要英语,因此只想使用ASCII.这对于用户 Joe来说可能没问题,但对软件开发人员 Joe来说这不太好.世界上大约一半的人使用非拉丁字符,使用ASCII可以说是对这些人不屑一顾,而且最重要的是,他正在关闭他的软件以适应经济规模庞大且不断发展的经济.

因此,需要包含所有语言的包含字符集.因此来了Unicode.它为每个角色分配一个称为代码点的唯一编号.Unicode优于其他可能集合的一个优点是前256个代码点与ISO-8859-1相同,因此也是ASCII.此外,在称为基本多语言平面(BMP)的区域中,绝大多数常用字符仅可由两个字节表示.现在需要一个字符编码来访问这个字符集,正如问题所示,我将专注于UTF-8和UTF-16.

记忆考虑

那么有多少字节可以访问这些编码中的字符?

  • UTF-8:
    • 1个字节:标准ASCII
    • 2个字节:阿拉伯语,希伯来语,大多数欧洲剧本(最值得注意的是不包括格鲁吉亚语)
    • 3个字节:BMP
    • 4个字节:所有Unicode字符
  • UTF-16:
    • 2个字节:BMP
    • 4个字节:所有Unicode字符

现在值得一提的是,BMP中没有的字符包括古代文字,数学符号,音乐符号和稀有的中文/日文/韩文(CJK)字符.

如果您将主要使用ASCII字符,那么UTF-8肯定更具内存效率.但是,如果您主要使用非欧洲脚本,那么使用UTF-8的内存效率可能比UTF-16低1.5倍.处理大量文本(如大型网页或冗长的文字文档)时,这可能会影响性能.

编码基础知识

注意:如果您知道如何编码UTF-8和UTF-16,请跳到下一节以了解实际应用.

  • UTF-8:对于标准ASCII(0-127)字符,UTF-8代码是相同的.如果现有ASCII文本需要向后兼容性,这使得UTF-8成为理想选择.其他字符需要2-4个字节.这是通过在每个字节中保留一些位来指示它是多字节字符的一部分来完成的.特别是,每个字节的第一位是1为了避免与ASCII字符冲突.
  • UTF-16:对于有效的BMP字符,UTF-16表示只是其代码点.但是,对于非BMP字符,UTF-16引入了代理对.在这种情况下,两个双字节部分的组合映射到非BMP字符.这些双字节部分来自BMP数字范围,但由Unicode标准保证为BMP字符无效.另外,由于UTF-16有两个字节作为基本单元,因此它受字节顺序的影响.为了补偿,可以在数据流的开头放置保留的字节顺序标记,以指示字节顺序.因此,如果您正在读取UTF-16输入,并且未指定任何字节顺序,则必须检查此项.

可以看出,UTF-8和UTF-16无法相互兼容.因此,如果您正在进行I/O,请确保您知道正在使用的编码!有关这些编码的更多详细信息,请参阅UTF常见问题解答.

实用的编程考虑

字符和字符串数据类型:它们如何用编程语言编码?如果它们是原始字节,那么在您尝试输出非ASCII字符的那一刻,您可能会遇到一些问题.此外,即使字符类型基于UTF,也不意味着字符串是正确的UTF.它们可能允许非法的字节序列.通常,您必须使用支持UTF的库,例如ICU for C,C++和Java.在任何情况下,如果要输入/输出默认编码以外的内容,则必须先进行转换.

推荐/默认/主导编码:当选择使用哪种UTF时,通常最好遵循您所使用的环境的推荐标准.例如,UTF-8在网络上占主导地位,而且从HTML5开始,它就是一直是推荐的编码.相反,.NET和Java环境都基于UTF-16字符类型.令人困惑(和错误地),通常对"Unicode编码"进行引用,这通常是指给定环境中的主要UTF编码.

库支持:您使用支持的库有哪些编码?他们是否支持角落案件?由于必要性是发明之母,UTF-8库通常会正确支​​持4字节字符,因为频繁出现1,2或3字节字符.但是,并非所有声称的UTF-16库都能正确支持代理对,因为它们很少发生.

计数字符: Unicode中存在组合字符.例如,代码点U + 006E(n)和U + 0303(组合波浪号)形成ñ,但代码点U + 00F1形成ñ.它们应该看起来相同,但是一个简单的计数算法将为第一个示例返回2,为后者返回1.这不一定是错的,但也可能不是理想的结果.

比较平等: A,А和Α看起来是一样的,但它们分别是拉丁语,西里尔语和希腊语.你也有C和cases等案例,一个是字母,另一个是罗马数字.另外,我们也要考虑组合字符.有关详细信息,请参阅Unicode中的重复字符.

代理对:这些在SO上经常出现,所以我只提供一些示例链接:

其他?:

  • 优秀的答案,丰厚的奖金机会;-)我个人补充说[有些人认为UTF-8是通用字符编码](http://www.utf8everywhere.org/),但我知道这是一个意见这并不一定是每个人共享的. (11认同)
  • 在这个阶段对我来说仍然太技术化了.如何将单词hello以UTF-8和UTF-16存储在计算机中? (3认同)
  • @mark有些位保留用于编码目的.对于以UTF-8占用2个字节的代码点,有5个保留位,只留下11位来选择代码点.U + 07FF最终成为2个字节中可表示的最高代码点. (2认同)

wen*_*ang 63

  • 统一
    • 是世界各地使用的一组字符
  • UTF-8
    • 一种能够编码Unicode中所有可能字符(称为代码点)的字符编码.
    • 代码单位是8位
    • 使用一到四个代码单元来编码Unicode
    • 00100100为" $ "(一个8位); 11000010 10100010 for" ¢ "(两个8位); 11100010 10000010 10101100 for" "(三个8位)
  • UTF-16
    • 另一个字符编码
    • 代码单位是16位
    • 使用一到两个代码单元来编码Unicode
    • 00000000 00100100为" $ "(一个16位); 11011000 01010010 11011111 01100010 for""(两个16位)


Neu*_*ron 27

Unicode是一个相当复杂的标准.不要太害怕,但要为一些工作做好准备![2]

因为总是需要可靠的资源,但官方报告很大,我建议阅读以下内容:

  1. 绝对最低每个软件开发人员绝对必须知道Unicode和字符集(没有借口!) Stack Exchange首席执行官Joel Spolsky的介绍.
  2. 对BMP及以后!技术总监Eric Muller,后来副总裁,在Unicode联盟的教程.(前20张幻灯片,你完成了)

简要说明:

计算机读取字节,人们读取字符,因此我们使用编码标准将字符映射到字节.ASCII是第一个广泛使用的标准,但仅涵盖拉丁语(7位/字符可代表128个不同的字符).Unicode是一个标准,其目标是覆盖世界上所有可能的字符(最多可容纳1,114,112个字符,意味着最多21位/字符.当前Unicode 8.0总共指定120,737个字符,这就是全部).

主要区别在于ASCII字符可以适合一个字节(8位),但大多数Unicode字符不能.因此使用编码表单/方案(如UTF-8和UTF-16),字符模型如下所示:

每个字符都有一个从0到1,114,111(十六进制:0-10FFFF)的枚举位置,称为代码点.
一个编码形式映射的码点到编码单元序列.一个代码单元是你想在内存中,8位,16位为单位来组织文字等方式.UTF-8使用1到4个8位单元,UTF-16使用1或2个16位单元,以覆盖最大21位的整个Unicode.单位使用前缀,以便可以发现字符边界,更多单位意味着占用比特的前缀更多.因此,尽管UTF-8使用1个字节用于拉丁文脚本,但它需要3个字节用于基本多语言平面内的后续脚本,而UTF-16使用2个字节用于所有这些.这是他们的主要区别.
最后,编码方案(如UTF-16BE或UTF-16LE)将代码单元序列映射(序列化)为字节序列.

字符:π
代码点:U + 03C0
编码格式(代码单位):
      UTF-8:CF 80
      UTF-16:03C0
编码方案(字节):
      UTF-8:CF 80
      UTF-16BE:03 C0
      UTF-16LE:C0 03

提示:十六进制数字代表4位,因此两位十六进制数字表示一个字节
另外,请查看维基百科中的平面地图,以了解字符集布局


dan*_*n04 18

最初,Unicode旨在具有固定宽度的16位编码(UCS-2).Unicode的早期采用者,如Java和Windows NT,围绕16位字符串构建了它们的库.

后来,Unicode的范围扩展到包括历史字符,这需要16位编码支持的超过65,536个代码点.为了允许在使用UCS-2的平台上表示其他字符,引入了UTF-16编码.它使用"代理对"来表示补充平面中的字符.

同时,许多较旧的软件和网络协议使用8位字符串.制作UTF-8使得这些系统可以支持Unicode而无需使用宽字符.它向后兼容7位ASCII.

  • 值得注意的是,Microsoft*仍然*将UTF-16称为Unicode,这增加了混乱.这两个*不是*相同. (3认同)

InG*_*eek 14

本文解释了所有细节 http://kunststube.net/encoding/

写作缓冲

如果你写一个4字节的缓冲区,?UTF8编码的符号,你的二进制文件将如下所示:

00000000 11100011 10000001 10000010

如果你写一个4字节的缓冲区,?UTF16编码的符号,你的二进制文件将如下所示:

00000000 00000000 00110000 01000010

如您所见,根据您在内容中使用的语言,这将相应地影响您的记忆.

例如,对于此特定符号:?UTF16编码效率更高,因为我们有2个备用字节用于下一个符号.但这并不意味着您必须将UTF16用于日本字母表.

从缓冲区读取

现在,如果您想要读取上面的字节,您必须知道它被写入的编码并正确解码.

例如,如果您将此解码: 00000000 11100011 10000001 10000010 转换为UTF16编码,您将最终?没有?

注意:编码和Unicode是两回事.Unicode是大(表),每个符号映射到唯一的代码点.例如,?符号(字母)有一个(代码点):30 42(十六进制).另一方面,编码是一种在存储到硬件时将符号转换为更合适的方式的算法.

30 42 (hex) - > UTF8 encoding - > E3 81 82 (hex), which is above result in binary.

30 42 (hex) - > UTF16 encoding - > 30 42 (hex), which is above result in binary.
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


bri*_*hty 9

为什么unicode?因为ASCII只有127个字符.那些128到255的国家在不同国家有所不同,这就是为什么有代码页.所以他们说让我们有1114111个字符.那么如何存储最高代码点?您需要使用21位存储它,因此您将使用具有32位且浪费了11位的DWORD.因此,如果使用DWORD存储unicode字符,则这是最简单的方法,因为DWORD中的值与代码点完全匹配.但是DWORD数组当然比WORD数组大,当然甚至比BYTE数组更大.这就是为什么不仅有utf-32,还有utf-16.但utf-16表示WORD流,而WORD有16位,那么最高代码点1114111如何适合WORD?这不可以!因此他们将高于65535的东西放入一个他们称为代理对的DWORD中.这样的代理对是两个单词,可以通过查看前6位来检测.那么utf-8怎么样?它是一个字节数组或字节流,但最高代码点1114111如何适合一个字节?这不可以!好吧,所以他们也装了DWORD吧?或者可能是一个词,对吗?几乎是对的!他们发明了utf-8序列,这意味着每个高于127的代码点必须编码为2字节,3字节或4字节序列.哇!但是我们怎样才能发现这样的序列?好吧,高达127的一切都是ASCII,是一个字节.以110开头的是一个双字节序列,以1110开头的是一个三字节序列,以11110开头的是一个四字节序列.这些所谓的"startbytes"的剩余部分属于代码点.现在,根据顺序,必须遵循以下字节.后续字节以10开头,其余位为6位有效负载位并属于代码点.连接startbyte和后续字节的有效负载位,你将获得代码点.这就是utf-8的神奇之处.

  • 以utf-8 3字节序列解码的€(欧元)符号的utf-8示例:E2 = 11100010 82 = 10000010 AC = 10101100如您所见,E2以1110开头,因此这是一个三字节序列正如您所见,82以及AC以10开始,因此这些是跟随字节现在我们连接"有效负载位":0010 + 000010 + 101100 = 10000010101100,这是小数8364所以8364必须是€(欧元)符号的代码点. (3认同)

Kis*_*wal 9

Unicode是一种标准,它将所有语言中的字符映射到称为代码点的特定数值.这样做的原因是,它允许使用相同的代码点集进行不同的编码.

UTF-8和UTF-16是两种这样的编码.它们将代码点作为输入,并使用一些明确定义的公式对它们进行编码,以生成编码字符串.

选择特定编码取决于您的要求.不同的编码具有不同的内存要求,并且根据您将要处理的字符,您应该选择使用最少字节序列来编码这些字符的编码.

有关Unicode,UTF-8和UTF-16的更深入的详细信息,您可以查看本文,

每个程序员应该了解的Unicode


小智 5

ASCII - 软件在内存中只为给定字符分配 8 位字节。它适用于英语和采用的(外来词,如 façade)字符,因为它们对应的十进制值在十进制值中低于 128。示例 C 程序。

UTF-8 - 软件为给定的字符分配 1 到 4 个可变的 8 位字节。这里的变量是什么意思?假设您通过浏览器中的 HTML 页面发送字符“A”(HTML 是 UTF-8),A 对应的十进制值为 65,当您将其转换为十进制时,它变为 01000010。这仅需要 1 个字节, 1 字节内存甚至分配给特殊采用的英文字符,如单词 façade 中的 'ç'。但是,当您要存储欧洲字符时,它需要 2 个字节,因此您需要 UTF-8。但是,当您使用亚洲字符时,最少需要 2 个字节,最多需要 4 个字节。同样,表情符号需要 3 到 4 个字节。UTF-8 将解决您的所有需求。

UTF-16 将为每个字符分配最少 2 个字节和最多 4 个字节,它不会分配 1 或 3 个字节。每个字符都以 16 位或 32 位表示。

那为什么会有UTF-16呢?最初,Unicode 是 16 位而不是 8 位。Java 采用了原始版本的 UTF-16。

简而言之,除非您正在使用的语言或平台已经采用了 UTF-16,否则您在任何地方都不需要 UTF-16。

Web 浏览器调用的 Java 程序使用 UTF-16,但 Web 浏览器使用 UTF-8 发送字符。