乐趣区

关于字符集:字符集和字符编码什么关系

严格来说,字符集和字符编码不是一个概念:

字符集 定义了字符和二进制的对应关系,为每个字符调配了惟一的编号。能够将字符集了解成一个很大的表格,它列出了所有字符和二进制的对应关系,计算机显示文字或者存储文字,就是一个查表的过程。

字符编码 规定了如何将字符的编号存储到计算机中。如果应用了相似 GB2312 和 GBK 的变长存储计划(不同的字符占用的字节数不一样),那么为了辨别一个字符到底应用了几个字节,就不能将字符的编号间接存储到计算机中,字符编号在存储之前必须要通过转换,在读取时还要再逆向转换一次,这套转换计划就叫做字符编码。

有的字符集在制订时就思考到了编码的问题,是和编码联合在一起的,例如ASCIIGB2312GBKBIG5 等,所以无论称作字符集还是字符编码都无所谓,也不好辨别两者的概念。而有的字符集只管制订字符的编号,至于怎么存储,那是字符编码的事件,Unicode 就是一个典型的例子,它只是定义了寰球文字的惟一编号,咱们还须要 UTF-8UTF-16UTF-32 这几种编码方案将 Unicode 存储到计算机中。

Unicode 能够应用的编码方案有三种,别离是:

  • UTF-8:一种变长的编码方案,应用 1~6 个字节来存储;
  • UTF-32:一种固定长度的编码方案,不论字符编号大小,始终应用 4 个字节来存储;
  • UTF-16:介于 UTF-8 和 UTF-32 之间,应用 2 个或者 4 个字节来存储,长度既固定又可变。

UTFUnicode Transformation Format 的缩写,意思是“Unicode 转换格局”,前面的数字表明至多应用多少个比特位 (Bit) 来存储字符。

1) UTF-8

UTF-8 的编码规定很简略:

  • 如果只有一个字节,那么最高的比特位为 0,这样能够兼容 ASCII;
  • 如果有多个字节,那么第一个字节从最高位开始,间断有几个比特位的值为 1,就应用几个字节编码,剩下的字节均以 10 结尾。

具体的表现形式为:

  • 0xxxxxxx:单字节编码模式,这和 ASCII 编码齐全一样,因而 UTF-8 是兼容 ASCII 的;
  • 110xxxxx 10xxxxxx:双字节编码模式(第一个字节有两个间断的 1);
  • 1110xxxx 10xxxxxx 10xxxxxx:三字节编码模式(第一个字节有三个间断的 1);
  • 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字节编码模式(第一个字节有四个间断的 1)。

xxx 就用来存储 Unicode 中的字符编号。

上面是一些字符的 UTF-8 编码实例(着色局部示意原本的 Unicode 编号):

字符 字母 N 符号æ 中文⻬
Unicode 编号(二进制) 01001110 11100110 00101110 11101100
Unicode 编号(十六进制) 4E E6 2E EC
UTF-8 编码(二进制) 01001110 11000011 10100110 11100010 10111011 10101100
UTF-8 编码(十六进制) 4E C3 A6 E2 BB AC

对于罕用的字符,它的 Unicode 编号范畴是 0 ~ FFFF,用 1~3 个字节足以存储,只有及其常见,或者只有多数地区应用的字符才须要 4~6 个字节存储。

2) UTF-32

UTF-32 是固定长度的编码,始终占用 4 个字节,足以包容所有的 Unicode 字符,所以间接存储 Unicode 编号即可,不须要任何编码转换。节约了空间,进步了效率。

3) UTF-16

UFT-16 比拟奇葩,它应用 2 个或者 4 个字节来存储。

对于 Unicode 编号范畴在 0 ~ FFFF 之间的字符,UTF-16 应用两个字节存储,并且间接存储 Unicode 编号,不必进行编码转换,这跟 UTF-32 十分相似。

对于 Unicode 编号范畴在 10000~10FFFF 之间的字符,UTF-16 应用四个字节存储,具体来说就是:将字符编号的所有比特位分成两局部,较高的一些比特位用一个值介于 D800~DBFF 之间的双字节存储,较低的一些比特位(剩下的比特位)用一个值介于 DC00~DFFF 之间的双字节存储。

如果你不了解什么意思,请看上面的表格:

Unicode 编号范畴(十六进制) 具体的 Unicode 编号(二进制) UTF-16 编码 编码后的字节数
0000 0000 ~ 0000 FFFF xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx 2
0001 0000—0010 FFFF yyyy yyyy yyxx xxxx xxxx 110110yy yyyyyyyy 110111xx xxxxxxxx 4

位于 D800~0xDFFF 之间的 Unicode 编码是特地为四字节的 UTF-16 编码预留的,所以不应该在这个范畴内指定任何字符。如果你真的去查看 Unicode 字符集,会发现这个区间内的确没有收录任何字符。

UTF-16 要求在制订 Unicode 字符集时必须思考到编码问题,所以真正的 Unicode 字符集也不是随便编排字符的。

比照以上三种编码方案

首先,只有 UTF-8 兼容 ASCII,UTF-32 和 UTF-16 都不兼容 ASCII,因为它们没有单字节编码。

1) UTF-8 应用尽量少的字节来存储一个字符,岂但可能节俭存储空间,而且在网络传输时也能节俭流量,所以很多纯文本类型的文件(例如各种编程语言的源文件、各种日志文件和配置文件等)以及绝大多数的网页(例如百度、新浪、163 等)都采纳 UTF-8 编码。

UTF-8 的毛病是效率低,岂但在存储和读取时都要通过转换,而且在解决字符串时也十分麻烦。例如,要在一个 UTF-8 编码的字符串中找到第 10 个字符,就得从头开始一个一个地检索字符,这是一个很耗时的过程,因为 UTF-8 编码的字符串中每个字符占用的字节数不一样,如果不从头遍历每个字符,就不晓得第 10 个字符位于第几个字节处,就无奈定位。

不过,随着算法的逐年精进,UTF-8 字符串的定位效率也越来越高了,往往不再是槽点了。

2) UTF-32 是“以空间换效率”,正好补救了 UTF-8 的毛病,UTF-32 的劣势就是效率高:UTF-32 在存储和读取字符时不须要任何转换,在解决字符串时也能最疾速地定位字符。例如,在一个 UTF-32 编码的字符串中查找第 10 个字符,很容易计算出它位于第 37 个字节处,间接获取就行,不必再一一遍历字符了,没有比这更快的定位字符的办法了。

然而,UTF-32 的毛病也很显著,就是太占用存储空间了,在网络传输时也会耗费很多流量。咱们平时应用的字符编码值个别都比拟小,用一两个字节存储足以,用四个字节几乎是暴殄天物,甚至说是不能容忍的,所以 UTF-32 在利用上不如 UTF-8 和 UTF-16 宽泛。

3) UTF-16 能够看做是 UTF-8 和 UTF-32 的折中计划,它均衡了存储空间和解决效率的矛盾。对于罕用的字符,用两个字节存储足以,这个时候 UTF-16 是不须要转换的,间接存储字符的编码值即可。

Windows 内核、.NET Framework、Cocoa、Java String 外部采纳的都是 UTF-16 编码。UTF-16 是幕后的功臣,咱们在编辑源代码和文档时都是站在前台,所以个别感触不到,其实很多文本在后盾解决时都曾经转换成了 UTF-16 编码。

不过,UNIX 家族的操作系统(Linux、Mac OS、iOS 等)内核都采纳 UTF-8 编码,咱们就不去争执谁好谁坏了。

宽字符和窄字符(多字节字符)

有的编码方式采纳 1~n 个字节存储,是变长的,例如 UTF-8、GB2312、GBK 等;如果一个字符应用了这种编码方式,咱们就将它称为多字节字符,或者窄字符。

有的编码方式是固定长度的,不论字符编号大小,始终采纳 n 个字节存储,例如 UTF-32、UTF-16 等;如果一个字符应用了这种编码方式,咱们就将它称为宽字符。

Unicode 字符集能够应用窄字符的形式存储,也能够应用宽字符的形式存储;GB2312、GBK、Shift-JIS 等国家编码个别都应用窄字符的形式存储;ASCII 只有一个字节,无所谓窄字符和宽字符。

援用:http://c.biancheng.net/view/v…

退出移动版