不知道大家都开始上网课了没,反正我是上了。这不,这两天一脸懵逼的学了编码字符集,上来写点东西巩固一下知识,要是有大佬能指点一下是再好不过了。。。
我就不介绍历史啥的了,就写一下自己这两天学到的东西吧。
浅谈一下自己对编码方式的了解。unicode规定了几乎所有文字的一个字符集,并给每个字符一个唯一的编码,每个字符对应一个唯一的4字节编码。4字节2^32大概能包含40多亿个字符吧,是足够的了。
其中第0个平面BMP(Basic Multilingual Plane基本多语言平面、基本多文种平面、基本平面、平面0),基本涵盖了当今世界上正在使用中的常用字符。我们平常用到的Unicode字符,一般都是位于BMP平面上的。
UTF-8
字节数不定但一般不多于4个字节。编码方式:
首字节开头表示该字符占几个字节(比如占2个字节就为110,3个1110)
接下来n个字节开头都为10用以区分单字节和多字节编码,这样做的好处在于避开了ASCII的同时保证了能表达的字符数足够,不过因此也导致了该编码字符字节与实际能表示的字符数有差异,如下图所示,2个字节其实有效位数为11位。。。
去除首字节开头的前缀码和接下来每个字节开头的10剩下的位按顺序组合在一起就是该字符的unicode编码,其实相当于用了一个巧妙的计算来建立unicode和UTF-8的映射
现在广泛应用的也是utf-8,效率高、数量大是它的优点(能包含2^21足够了)
UTF-16
UTF-16在大多数情况下是与unicode编码相同的。UTF-16想用2个字节来表示所有的字符,但实际上2个字符只能表示BMP这个基本平面内的字,虽然一般情况下是够用的了,但还是需要补增平面来充数。。。在不够的情况下采用代理机制,BMP平面内有一个代理区其码点编号范围为0xD8000xDFFF(十进制5529657343),共2048个码点,这个区域内的编码不表示任何字符,专门用作代理。此时UTF-16就采用4字节的编码方式前两个字节用来存储代理点的编码,
增补平面一共有16个平面(即第2平面第17平面),码点编号范围为0x100000x10FFFF(十进制为655361114111,码点总数为1048576个)。用两个代理码元表示,第一个码元的取值范围为0xD8000xDBFF(二进制为1101 1000 0000 0000 ~ 1101 1011 1111 1111,十进制为55296 ~ 56319),第二个码元的取值范围为0xDC00~0xDFFF(二进制为1101 1100 0000 0000 ~ 1101 1111 1111 1111,十进制为56320 ~ 57343)。
因此,增补平面的第一个码点的编号0x10000其UTF-16编码就是0xD800 0xDC00(即0x10000经UTF-16编码后的码元序列为0xD800 0xDC00),其余类推。展现为二进制形式后如下:
代理码元1 代理码元2
1101 10pp ppxx xxxx 1101 11xx xxxx xxxx
其中代理码元1中的110110、代理码元2中的110111是定数,p、x是变数。去掉定数后组合起来就是pppp xxxx xxxx xxxx xxxx,共20位(220=1048576),刚好能够表示增补平面中的全部码点(0x10000~0x10FFFF,共1048576个)。其中pppp共4位,表示16个增补平面之一的编号(24=16);紧接着的16位x表示某个增补平面内的某个码点(2^16=65536,而65536*16=1048576)。
按照上面的编码方式,代理对里面的两个代理码元分别称之为高16位代理码元(或称为lead surrogates引导代理、前导代理),和低16位代理码元(或称为trail surrogates尾随代理、后尾代理)。
由于引导代理和尾随代理的值分别在0xD800~0xDBFF(十进制为55296 ~ 56319)之间和0xDC00~0xDFFF(十进制为56320 ~ 57343)之间,所以首尾两个代理总共可以组合出(56319-55296+1)(57343-56320+1)=1048576个代理对,也就是总共可以表示1048576个增补码点,而目前Unicode标准所确定的16个增补平面的码点总和也就是6553616=1048576个。
从增补平面的码点值通过基本平面中的代理对编码为增补平面字符的码元序列的具体算法如下:
1) 增补平面中的码点值(0x10000~0x10FFFF,二进制为0001 0000 0000 0000 0000~1 0000 1111 1111 1111 1111,对应的字符名称为U+10000~U+10FFFF)减去0x10000(二进制为0001 0000 0000 0000 0000),可得到20位长的比特组(值的范围为0x00000~0xFFFFF,二进制为0000 0000 0000 0000 0000 ~ 1111 1111 1111 1111 1111);
2)将得到的20位长的比特组分拆为两部分:高位10比特和低位10比特;
3)20位长的比特组中的高位10比特(值的范围为0x000~0x3FF,二进制为00 0000 0000~11 1111 1111)加上0xD800(二进制为1101 1000 0000 0000),得到第一个代理码元即引导代理(值的范围是0xD800~0xDBFF,二进制为1101 1000 0000 0000 ~ 1101 1011 1111 1111);
4)20位长的比特组中的低位10比特(值范围也是0x000~0x3FF,二进制为00 0000 0000~11 1111 1111)加上0xDC00(二进制为1101 1100 0000 0000),得到第二个代理码元即尾随代理(值的范围是0xDC00~0xDFFF,二进制为1101 1100 0000 0000 ~ 1101 1111 1111 1111);
5)将引导代理与尾随代理按前后顺序组合在一起成为“代理对”,就得到了增补平面字符的码元序列。
例如,增补平面中码点值为10437(字符名称为U+10437)的字符(𐐷):
1)0x10437减去0x10000,结果为0x00437,二进制为0000 0000 0100 0011 0111。
2)分拆成高10位值和低10位值两部分:0000000001(即0x0001)及0000110111(即0x0037)。
3)添加0xD800到高位值,以形成高位的引导代理:0xD800 + 0x0001 = 0xD801(二进制为1101 1000 0000 0001)。
4)添加0xDC00到低位值,以形成低位的尾随代理:0xDC00 + 0x0037 = 0xDC37(二进制为1101 1100 0011 0111)。
5)将高位的引导代理与低位的尾随代理按前后顺序组合在一起成为“代理对”,就得到了增补平面字符𐐷(字符名称为U+10437)的码元序列:1101 1000 0000 0001 1101 1100 0011 0111。
下表总结了该转换。不同的颜色表示码点值是如何被分布到UTF-16码元序列中的,而由UTF-16编码过程中加入的代理附加位则以不同的红色(亮红色与暗红色)显示:
此处引用https://www.cnblogs.com/benbenalin/p/7152570.html
大家可以看看这个大神写的文章,很全面。
GBK:双字节编码,首字节大于127。用以区分ASCII