第四章:编号如何转化成encoding

encoding长度问题

当我们在网络传输信息的时候,底层是按照0/1方式来传输,问题来了,当接收方接收到一连串0/1之后,接收方该如何分割0/1字符串呢?

ASCII一开始1字节(8位)来传输,后来GB2312采取变长方式来编码,这是因为当遇到汉字时采取2字节编码,遇到ASCII再用1字节编码,说白了GB2312动态变化主要是为了兼容1字节的ASCII。

再加上其他国家的国家标准,因此不同长度的编码方式层出不穷,为了方便计算机在全世界推广,解决不同国家编码长度不同的问题,为此发明了Unicode字符集。

Unicode一开始是按照固定2字节的方式来推广,即2^16次方个字符(有些软件Unicode字符集的编码默认是UTF16的原因),后来发现固定2字节还是不够,还得继续扩充。但是在扩容的时候发现一个问题:虽然字节越多,其表示的字符量越大,但是这会导致字符在内存中占据较大的容量,进而有点浪费内存。

如果采用定长编码方式的话,那么该定多长是个问题,另外有些生僻字符被用到的概率很小,即便用也就是用几次而已,有必要为小概率字符而设置较长的定长编码方式吗??????

UTF16采用2字节存储ASCII码,为了解决浪费问题,发明了UTF8来解决这个问题,当然UTF8也可以用3字节或者4字节来存储汉字,说实话,在中英文混杂的情况下,UTF8的效率比不上GBK、GB2312等。

因此结合上面信息,Unicode最后采用变长的编码方案。下面重点讲解变长的规则:

这里还是要回到编号上面,由于是一个二维平面,因此每个编号都会用一个“码点”来表示。

码点是用U+[XX]XXXX形式来表示,X代表一个十六制数字,最少为4位,最长为6位,不足4位的前补0补足4位,超过4位则按是几位就是几位。

码点取值范围时U+0000~U+10FFFF,这里是按照最短4位、最长6位的方式来编写,因此:

从U+0000到U+FFFF一共有65536个码点,

而从U+FFFF到U+10FFFF即有10个FFFF,由于是16进制,这里的10换成十进制就是17,也就是一共有17个65535。

为了方便管理这17个65535,Unicode把每65536个码点看成一个平面,这样就一共有17个平面(Plane),平面编号从0开始直到16。

其中第一个平面即Plane0叫做BMP,它的码点范围是U+0000到U+FFFF,该平面内的字符是我们最常用的平面,日常用到的字符绝大多数都落在这个平面内,因此当UTF-16遇到此平面内的字符时只需要用两字节来编码字符。

每个Plane都是一个256×256=65536的表格,横向/纵向都是从 00到FF。

Plane1-Plane16叫做增补平面(SP),对于这些平面内的字符,UTF-16采用了四字节编码。

码点与UTF-32转换

我们说码点最大的 10FFFF 也就 21 位,而

UTF-32采用的是定长4字节,即32位。而Unicode最大10FFFF 也就21位,所以只要把码点的表示形式以前补0的形式补够32位即可。

码点与UTF-8转换

UTF-8是变长的编码方案,其长度分为:1字节、2字节、3字节、4字节。

UTF-8采用高位保留方式来区别不同变长:

1字节:0XXXXXXX

2字节:110XXXXX 10XXXXXX

3字节:1110XXXX 10XXXXXX 10XXXXXX

4字节:11110XXX 10XXXXXX 10XXXXXX 10XXXXXX 10XXXXXX

保留的高位是固定位,固定不变的。X表示是有效编码位。

1字节最高位都是0,多字节的最高位都是1。可以总结为:N字节模式(N>1),首字节以N个1再加0来打头,后跟N-1个以10打头的字节。

那码点具体如何从这4种编码方式中选择呢?

先把码点变成二进制,然后看它有多少有效位(去掉前导0)来确定编码方式:

1字节:因为1字节有效编码为就7个,因此码点有效编码位有7位的话,就用1字节来编码。1字节主要是留给ASCII,所以UTF-8兼容ASCII。码点 U+0000到U+007F(0~127)

2字节:2字节有效编码位只有11位,只有2^11=2048个编码空间,所以无法存放汉字。码点 U+0080到U+07FF(128~2047)使用二字节。

3字节:3字节有效编码位是16位,因此2^16=65536个,码点U+0800到U+FFFF(2048~65535)使用三字节编码。常用的汉字就落在这个区间。

4字节:4字节有效位是21 位,前面说到最大的码点10FFFF也是21位,U+FFFF以上的增补平面的字符都在这里来表示。

按照UTF-8的模式,它还可以扩展到5字节、6字节甚至更长,但Unicode规定码点就到10FFFF,不扩充了,所以UTF-8最多到四字节就足够了。

码点与UTF-16转换

UTF-16是一种变长的2或4字节编码模式。对于Plane0 BMP内的字符使用2字节编码,其它的则使用4字节组成所谓的代理对来编码。

先说说代理区:

00

...

FF

...

 

 

D8

 

 

D9

 

 

DA

 

 

DB

 

 

DC

 

 

DD

 

 

DE

 

 

DF

 

 

上面是Plane0即BMP中,纵向从D8到DF,这8行是空白行。其中D8到DB属于高代理区,而DC到DF属于低代理区。

这样各个代理区就有:4 * 256 = 1024个。

这样的话,高代理区有如下编号:

D800-D8FF  D900-D9FF  DA00-DAFF  DB00-DBFF共1024个。

同样低代理区就有:

DC00-DCFF  DD00-DDFF  DE00-DEFF  DF00-DFFF共1024个。

当把一个D8-DB共1024个编号当做竖坐标,而DC-DF当做横坐标,这个平面二维表格就有1024*1024=16*65536个表格。

而后面也恰恰有16个增补平面,即:Plane1-Plane16,正好可以容纳后面16个增补平面的字符量。

再说说代理对:

一个高代理区(D8-DB竖坐标)的加一个低代理区(DC-DF横坐标)的编码组成一对即是一个代理对,必须是这种先高后低的顺序。

再回到原题,即码点与UTF-16如何转换?

首先,BMP中直接对应的,无须做任何转换,直接2字节存储。

其次,位于增补平面SP中的,这就需要计算其代理对是多少,有点复杂,这里就不讲了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值