什么是Unicode、UTF-8和UTF-16?

Unicode的基础是什么?为什么需要UTF-8或UTF-16? 我在谷歌上研究过这个,也在这里搜索过,但我不清楚

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

请简单解释一下。

346119 次浏览

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

后来,Unicode的范围扩大到包括历史字符,这将需要超过16位编码所支持的65,536个编码点。为了允许在使用UCS-2的平台上表示额外的字符,引入了UTF-16编码。它使用“代理对”;表示补充平面上的字符。

与此同时,许多旧的软件和网络协议使用8位字符串。UTF-8是为了让这些系统可以支持Unicode而不必使用宽字符。它向后兼容7位ASCII。

为什么我们需要统一码?

在(不是太)早期,所有存在的都是美国信息交换标准代码。这是可以的,因为所需要的只是一些控制字符、标点符号、数字和字母,就像这句话中的这些。不幸的是,今天这个全球相互交流和社交媒体的陌生世界并没有被预见到,在同一份文件中看到英文、العربية、汉语、ְִרִי、ελληνικ和ភាសាខ្មែរ也不是太罕见(希望我没有弄坏任何旧浏览器)。

但是为了讨论,让我们假设Joe Average是一个软件开发人员。他坚持说他永远只需要英语,因此他只想使用ASCII码。这对Joe the 用户可能没问题,但这对Joe the 软件开发人员就不行。世界上大约有一半的人使用非拉丁字符,使用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倍。在处理大量文本时,如大网页或冗长的word文档,这可能会影响性能。

编码的基本知识

注:如果您知道UTF-8和UTF-16是如何编码的,请跳过下一节了解实际应用

  • utf - 8:对于标准ASCII(0-127)字符,UTF-8代码是相同的。这使得UTF-8成为与现有ASCII文本向后兼容的理想选择。其他字符需要2-4字节。这是通过在每个字节中保留一些位来完成的,以表明它是多字节字符的一部分。特别是,每个字节的第一位是1,以避免与ASCII字符冲突。
  • 对于有效的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的库,比如C、c++和Java的加护病房。在任何情况下,如果您想输入/输出缺省编码以外的内容,则必须首先对其进行转换。

当要选择使用哪种UTF时,通常最好遵循所处环境的推荐标准。例如,UTF-8在web上占主导地位,自HTML5以来,它一直是推荐的编码。相反,netJava环境都建立在UTF-16字符类型上。令人困惑(和不正确)的是,经常引用“Unicode编码”,这通常指的是给定环境中的主要UTF编码。

图书馆支持:你使用的库支持某种编码。哪一个?他们支持极端情况吗?因为需要是发明之母,UTF-8库通常会正确地支持4字节字符,因为1、2甚至3字节字符经常出现。然而,并不是所有的UTF-16库都正确地支持代理对,因为它们很少出现。

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

平等比较: A, А和Α看起来一样,但它们分别是拉丁语,西里尔语和希腊语。你也有C和Ⅽ这样的情况。一个是字母,另一个是罗马数字。此外,我们还需要考虑组合字符。有关更多信息,请参见 Unicode中出现重复字符

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

为什么Unicode ?因为ASCII只有127个字符。128到255在不同的国家是不同的,这就是为什么会有代码页。所以他们说:让我们有1114111个字符。

那么如何存储最高码位呢?您需要使用21位存储它,因此您将使用一个32位的DWORD,浪费了11位。因此,如果使用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开头的是一个四字节序列。剩下的部分被称为“起始字节”;属于码位。

现在,根据序列的不同,后面的字节必须跟着。后面的字节以10开头,其余位为有效负载位的6位,属于码位。将开始字节的有效负载位和后面的字节/秒连接起来,就得到了代码点。这就是UTF-8的魔力所在。

    <李> Unicode
    • 一套字符在全世界都使用吗
    • 李< / ul > < / > <李> utf - 8
      • 能够编码Unicode中所有可能的字符(称为码位)的字符编码。
      • 编码单位为8位
      • 使用一到四个编码单元来编码Unicode
      • 00100100用于""(一个8位);11000010 10100010用于"¢"(两个8位);11100010 10000010 10101100用于""(三个8位)
      • 李< / ul > < / > <李> utf - 16
        • 另一种字符编码
        • 编码单位为16位
        • 使用一到两个编码单元来编码Unicode
        • 00000000 00100100用于""(一个16位);11011000 01010010 11011111 01100010用于"𤭢"(两个16位)
        • 李< / ul > < / >
Unicode是一个相当复杂的标准。不要太害怕,但要做 为一些工作做准备![2] < / p >

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

  1. Stack Exchange首席执行官Joel Spolsky的介绍。
  2. 为BMP和超越!由Unicode联盟的技术总监,后来的副总裁Eric Muller所做的教程(前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使用一到四个单位的8位,UTF-16使用一个或两个单位的16位,以覆盖整个最大21位的Unicode。单位使用前缀,这样可以发现字符边界,更多的单位意味着更多的前缀占用比特。因此,尽管UTF-8为拉丁脚本使用一个字节,但它需要三个字节用于基础多语言平面中的后续脚本,而UTF-16为所有这些脚本使用两个字节。这就是它们的主要区别。
最后,编码方案(如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

提示:十六进制数字代表四位,所以两位十六进制数字代表一个字节。
还可以看一下维基百科的平面地图来了解字符集布局

UTF代表Unicode转换格式。基本上,在当今世界,有数百种其他语言编写的脚本,这些脚本的格式不包括在以前使用的基本ASCII中。因此,UTF应运而生。

UTF-8具有字符编码功能,其代码单位为8位,而UTF-16为16位。

文章每个程序员都绝对,积极地需要了解编码和字符集来处理文本解释了所有细节。

写入缓冲区

如果你写入一个4字节的缓冲区,符号使用UTF8编码,你的二进制将看起来像这样:

00000000 11100011 10000001 10000010

如果你写入一个4字节的缓冲区,符号使用UTF16编码,你的二进制将看起来像这样:

00000000 00000000 00110000 01000010

正如你所看到的,根据你在内容中使用的语言,这将相应地影响你的记忆。

例如:对于这个特殊的符号: UTF16编码更有效,因为我们有2个空闲字节用于下一个符号。但这并不意味着你必须使用UTF16来表示日本字母。

从缓冲区读取

现在,如果你想读取上面的字节,你必须知道它是用什么编码写的,并正确解码回来。

< p >。如果你解码这个: 00000000 11100011 10000001 10000010 转换为UTF16编码,你将得到而不是

注意: Encoding和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.

Enter image description here

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

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

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

有关Unicode, UTF-8和UTF-16的更多详细信息,您可以查看这篇文章,

每个程序员都应该知道的关于Unicode的知识

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

UTF-8 -软件为一个给定的字符分配一到四个可变的8位字节。这里的变量是什么意思?假设您正在通过浏览器中的HTML页面(HTML是UTF-8)发送字符“A”,对应的十进制值A是65,当您将其转换为十进制时,它就变成了01000010。这只需要一个字节,甚至为特殊的英语字符分配一个字节的内存,比如单词外观中的'ç'。但是,当您想要存储欧洲字符时,它需要两个字节,因此需要UTF-8。但是,当您使用亚洲字符时,您需要最少两个字节,最多四个字节。类似地,表情符号需要3到4个字节。UTF-8将解决您的所有需求。

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

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

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

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