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

Unicode的基础是什么,为什么需要UTF-8或UTF-16? 我在Google上研究过这个,也在这里search,但是对我来说还不清楚。

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

请简单说明一下。

为什么我们需要Unicode?

在(不太)早期,所有存在的是ASCII。 这是可以的,因为所有需要的都是一些控制字符,标点符号,数字和字母,就像这句话中的那些。 不幸的是,今天的全球互通和社交媒体这个陌生的世界是没有预见到的,在同一份文件中看到英文,العربية,汉语,古巴文,ελληνικά和ភាសាខមែរ(我希望我没有打破旧的浏览器)。

但是为了论证的缘故,可以说Joe Average是一名软件开发人员。 他坚持认为他只会需要英文,因此只想使用ASCII。 Joe对用户来说可能没问题,但是这对软件开发人员 Joe来说并不好。 世界上大约有一半人使用非拉丁字符,使用ASCII对这些人来说可能是不合理的,而且,他正在closures他的软件,以适应一个庞大的,不断增长的经济。

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

内存考虑

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

  • UTF-8:
    • 1个字节:标准ASCII
    • 2个字节:阿拉伯文,希伯来文,大部分欧洲文字(最显着的不包括格鲁吉亚文 )
    • 3个字节:BMP
    • 4个字节:所有Unicode字符
  • UTF-16:
    • 2个字节:BMP
    • 4个字节:所有Unicode字符

现在值得一提的是,不在BMP中的字符包括古文字,math符号,音乐符号,以及较less的中日韩文字符(CJK) 。

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

编码基础知识

注意:如果您知道如何编码UTF-8和UTF-16,请跳至下一节以获取实际应用。

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

可以看出,UTF-8和UTF-16是远不相容的。 所以,如果你正在做I / O,确保你知道你正在使用哪种编码! 有关这些编码的更多详细信息,请参阅UTF常见问题解答 。

实际的编程考虑

字符和string数据types:它们如何在编程语言中编码? 如果它们是原始字节,那么当您尝试输出非ASCII字符时,可能会遇到一些问题。 而且,即使字符types是基于UTF的,也并不意味着string是正确的UTF。 他们可能会允许字节序列是非法的。 通常,您必须使用支持UTF的库,例如C,C ++和Java的ICU 。 在任何情况下,如果你想input/输出默认编码以外的东西,你将不得不先转换它。

推荐/默认/主导编码:当select使用哪个UTF时,通常最好遵循所使用环境的推荐标准。例如,UTF-8在Web上占主导地位,而从HTML5开始已被推荐的编码 。 相反,.NET和Java环境都build立在UTF-16字符types上。 混淆(而且不正确),通常引用“Unicode编码”,它通常指给定环境中的主导UTF编码。

库支持:您正在使用的库支持哪些编码? 他们是否支持angular落案件? 由于必要性是发明之母,因此UTF-8库通常会正确支​​持4字节字符,因为1,2,甚至3字节字符会频繁出现。 然而,并不是所有的声称的UTF-16库都支持代理对,因为它们很less发生。

计数字符: Unicode中存在组合字符。 例如,代码点U + 006E(n)和U + 0303(一个组合代字符)形成了ñ,但代码点U + 00F1形成了ñ。 他们看起来应该是一样的,但是一个简单的计数algorithm将会返回2,第一个例子是1,后者是1。 这不一定是错误的,但也可能不是预期的结果。

比较平等: A,A和A看起来相同,但分别是拉丁文,西里尔文和希腊文。 你也有类似C和cases的情况,一个是字母,另一个是罗马数字。 另外,我们也有相结合的angular色来考虑。 有关更多信息,请参阅Unicode中的重复字符 。

替代对:这些对于SO来说足够常用,所以我只提供一些示例链接:

  • 获取string长度
  • 删除代理对
  • 回文检查

其他?:

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

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

因为总是需要一个可信的资源,但是官方的报告是巨大的,我build议阅读以下内容:

  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字符不能。 所以使用编码forms/scheme(如UTF-8和UTF-16),字符模型如下所示:

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

字符:π
代码点:U + 03C0
编码forms(代码单元):
UTF-8:CF 80
UTF-16:03C0
编码scheme(字节):
UTF-8:CF 80
UTF-16BE:03 C0
UTF-16LE:C0 03

提示:hex数字表示4位,所以两位hex数字表示一个字节
另外请看维基百科的平面地图,以获得angular色集布局的感觉

最初,Unicode意在具有固定宽度的16位编码(UCS-2)。 Unicode的早期采用者(如Java和Windows NT)以16位string为基础构build了它们的库。

之后,Unicode的范围扩展到包含历史字符,这将需要16位编码将支持的65536个以上的代码点。 为了允许在使用UCS-2的平台上表示附加字符,引入了UTF-16编码。 它使用“代理对”来表示辅助平面中的angular色。

同时,许多较旧的软件和networking协议正在使用8位string。 UTF-8是这样制作的,所以这些系统可以支持Unicode而不必使用宽字符。 它与7位ASCII向后兼容。

为什么unicode? 因为ASCII只有127个字符。 那些从128到255的国家在不同国家有所不同,这就是为什么有代码页。 所以他们说让我们有1114111个字符。 那么如何存储最高的编码点呢? 你需要使用21位存储它,所以你将使用一个32位的DWORD,浪费11位。 因此,如果使用DWORD来存储Unicode字符,则这是最简单的方法,因为DWORD中的值与代码点完全匹配。 但是DWORD数组当然比WORD数组大,当然比BYTE数组还要大。 这就是为什么不仅有utf-32,而且还有utf-16。 但是utf-16意味着一个WORDstream,而一个WORD有16个位,那么最高的代码点1114111怎样才能embedded到WORD中呢? 这不可以! 所以他们把每一个高于65535的东西都放进一个他们称之为代理对的DWORD中。 这样的替代对是两个字,可以通过查看前6位来检测。 那么utf-8呢? 它是一个字节数组或字节stream,但最高代码点1114111如何适合一个字节? 这不可以! 好吧,所以他们也放了一个DWORD的权利? 或者可能是一个字,对吗? 几乎正确! 他们发明了utf-8序列,这意味着每个高于127的代码点必须被编码成2个字节,3个字节或者4个字节的序列。 哇! 但是我们如何检测这样的序列呢? 那么,127以上的所有内容都是ASCII码,是一个字节。 以110开始的是两字节序列,以1110开始的是三字节序列,以11110开头的序列是四字节序列。 这些所谓的“起始字节”的其余部分属于码点。 现在取决于序列,必须遵循以下字节。 接下来的字节从10开始,其余的位是有效载荷位的6位,属于码点。 连接起始字节和接下来的字节/秒的有效负载位,你将得到代码点。 这就是utf-8的全部魔力。

这篇文章解释了所有的细节http://kunststube.net/encoding/

写给缓冲区

如果你写了一个4字节的缓冲区,用UTF8编码写出 ,你的二进制文件看起来像这样:

00000000 11100011 10000001 10000010

如果你写了一个4字节的缓冲区,用UTF16编码写 ,你的二进制文件看起来像这样:

00000000 00000000 00110000 01000010

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

例如,对于这个特定的字母:由于我们有2个备用字节用于下一个符号,因此使用UTF16更高效。 但是,这并不意味着你必须使用UTF16日本字母表。

从缓冲区读取

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

例如,如果你编码: 00000000 11100011 10000001 10000010到UTF16你最终将

在这里输入图像说明

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

UTF-8和UTF-16是两种这样的编码。 他们将代码点作为input,并使用一些定义良好的公式来编码它们以产生编码的string。

select一个特定的编码取决于你的要求。 不同的编码具有不同的内存要求,根据您要处理的字符,您应该select使用最less字节序列编码这些字符的编码。

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

每个程序员应该了解Unicode

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

UTF-8具有字符编码能力,其编码单位是8位,而UTF-16则是16位。

一个IDN(国际域名)域,并使用Unicode(UTF-8)来格式化域。 域IDN转换工具可帮助您将ASCII域转换为Unicode和Unicode域以ASCII。

在这里试试unicode: Unicode转换工具