Interview--zaza

Unicode与UTF-8的区别

ASCII码

在计算机的世界里,信息的表示方式只有0和1,但是人类信息的表示方式却与之大不相同,很多时候是用语言文字、图像、声音等传递信息的

怎么将其转化为二进制存储到计算机中,这个过程我们称之为编码

在计算机中每八个二进制位组成了一个字节(byte),计算机存储的最小单位就是字节

早期人们用8位二进制来编码英文字母(最前面的一位是0),将英文字母和一些常用的字符和这128中二进制0、1串一一对应起来,但是其他国家的字符和英文是用出入的,所以各个国家把字节中最前面未使用的那一位来使用,原来的128种状态就变成了256种

为了保持与ASCII码的兼容性,一般最高位为0时和原来的ASCII码相同,最高位为1时,各个国家给后面的位(1XXX XXXX)赋予他们国家的字符意义

不同的国家对新增的128个数字赋予了不同的含义,不同的国家有不同国家的编码方式,如果给一串二进制数,想要解码,就必须知道他的编码方式,不然就会出现我们有时候看到的乱码

Unicode

为世界上所有字符都分配了一个唯一的数字编号,这个范围从0x000000到0x10ffff(十六进制),有110多万,每个字符都有唯一的Unicode编号,这个编号一般写成16进制,例如:“马”的Unicode是U+9A6C

Unicode相当于建立了一张表,建立了字符与编号之间的联系

它是一种规定,Unicode本身只规定了每个字符的数字编号是多少,没有规定这个编号如何存储

编号对应到二进制表示:UTF-8, UTF-16, UTF-32

UTF-32

这个就是字符对应编号的整数的二进制形式,四个字节,直接转换,例如:马的Unicode为U+9A6C,那么直接转化为二进制,它的表示就为:1001 1010 0110 1100。

需要说明的是,转换成二进制后计算机存储问题,有两种排列字节的方式,big-endian and small-endian,big-endian大端法就是将高为字节放到低地址处,比如0x1234,计算机用两个字节存储,一个是高位字节0x12,一个是低位字节0x34,他的存储方式为:

..|12|34|..  高位字节存储在低地址处

  ..|0x100|0x101|..   地址由低到高

在编码方式中有UTF-32BE和UTF-32LE,分别对应big-endian and small-endian

UTF-16

UTF-16使用变长字节表示

  • 对于编号在U+0000到U+FFFF的字符(常用字符集),直接用两个字节表示
  • 对于编号在U+10000到U+10FFFF之间的字符,需要用四个字节表示

同样,UTF-16也有字节的顺序问题big-endian and small-endian,就有UTF-16BE表示大端,UTF-16LE表示小端

UTF-8

UTF-8就是使用变长字节表示,使用的字节数可变,这个变化是根据Unicode编号的大小有关,编号小的使用的字节就少,编号大的使用的字节就多,使用的字节个数从1到4不等

UTF-8编码规则:

  • 对于单字符的符号,字节的第一位设为0,后面的7位为这个符号的Unicode码,因为对应英文字母,UTF-8编码和ASCII码是相同的
  • 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10,剩下的没有提及的二进制位,全部为这个符号的Unicode码

例如:一个字符的Unicode编码是130,显然按照UTF-8的规则一个字节是表示不了它(因为如果是一个字节的话前面的一位必须是0),所以需要两个字节(n = 2)。根据规则,第一个字节的前 2 位都设为1,第3(2+1)位设为0,则第一个字节为:110X XXXX,后面字节的前两位一律设为10,后面只剩下一个字节,所以后面的字节为:10XX XXXX。所以它的格式为110XXXXX 10XXXXXX

比如:“马”的Unicode编号是:0x9A6C,整数编号是39532,对应第三个范围(2048 - 65535),其格式为:1110XXXX 10XXXXXX 10XXXXXX,39532 对应的二进制是 1001 1010 0110 1100,将二进制填入进入就为:11101001 10101001 10101100 。

由于UTF-8的处理单元为一个字节(也就是一次处理一个字节),所以处理器在处理的时候就不需要考虑这一个字节的存储是在高位还是在低位,直接拿到这个字节进行处理就行了,因为大小端是针对大于一个字节的数的存储问题而言的

总结自wx公众号:趣谈编程