首先我们来思考UTF-16的设计思路:
我们知道Unicode的范围为0x0~0x10FFFF
首先是BMP区间,也就是0x0~0xFFFF这段区间,正好16位就可以表示,也兼容,两全其美
那么超过BMP区间的怎么办呢?
也就是0xFFFF~0x10FFFF这段,我们先看这段区间有多少个码位,0x10FFFF-0xFFFF=0x100000,那么这个十六进制表示的十进制也就是:1048576个码位
我们既然16位存不下,那肯定就是32位存咯,这个32能理解为什么不?不理解?是因为计算机只能以2的倍数拓展,如果不这么设计,就没办法解析。长短不一,不符合设计思路
32位来存这些数字,那么我们需要怎么存下呢,简单的思考过后,大家认为应该分开存储,也就是将32位分开前16位和后16位,每个16位各存一半
那么每一半存的就是1024(由来:√1048576=1024,也就是1024*1024=1048576),1024代表的是2的10次幂,也就是10位二进制数
这样就知道了,32位二进制数字中,前后16位中各存10位就够用了,但是剩余的6位用来干什么呢?
和UTF-8的设计一样,为了让识别字符串变得容易(从文本的任意位置开始,均能区分一个字符的起始),这里是不是有点儿蒙?
举个栗子:
假设:
0000 0001 代表A
0000 0010 代表B
0000 0001 ,0000 0001 代表 X
0000 0010 ,0000 0001 代表Z
那么 ABXZ就是
0000 0001 ,0000 0010 , 0000 0001 ,0000 0001 , 0000 0010,0000 0001
A B X Z
但是让你从中间开始读取,当你读到X的时候,你不知道他是X还是 AB,这样就很麻烦,你需要设置标志,来让16位的数据的前8或后8不会和单个8位的重复
可以这样设计:
0xxx xxxx 代表0~2^7
11xx xxxx ,10xx xxxx 代表其他的
这样就能区分开了,当你读到11开头的,就代表他是16位的前8,10开头代表16位的后8
欧了,有了这个思路,我们就知道怎么设计刚才的那个6位了,当然是通过这6位来区分这16位数字代表的位置
也就是UTF-16中,表示数据有单16位和双16位(32位)两种,那么我们设计成单16位和32位中的前16位和后16位这三个16位完全不会重复,那么我们就能随时读到一组16位,就能知道他是单16还是前16还是后16
举个栗子:
根据上方信息,要求我们通过前6位来区分数据,那么前6位就是2^6=64,也就是开头数字的区间
我们设定如下:
54开头的为32位的前16位
55开头的为32位的后16位
其他开头的为单16位
这样我们就能区分开这三个16位了,在读取文档中的任意位置,都能随意区分出间隔咯
那么54开头的数据区间是多少呢,就是1101 10xx xxxx xxxx,区间就是D800~DBFF
那么55开头的数据区间是多少呢,就是1101 11xx xxxx xxxx,区间就是DC00~DFFF
为了配合UTF-16,Unicode中也将这两个区间屏蔽掉,不允许分配任何字符
下方为比较官方的关于UTF-16的编码详解
参考文献:
https://en.wikibooks.org/wiki/Unicode/Character_reference/D000-DFFF
根据参考文献中所示,D800~DFFF为专门提供给UTF-16专用,原文如下:
Unicode range D800–DFFF is used for surrogate pairs in UTF-16 (used by Windows) and CESU-8 transformation formats,
Unicode范围D800-DFFF用于UTF-16(由Windows使用)和CESU-8转换格式的代理对,
allowing these encodings to represent the supplementary plane code points, whose values are too large to fit in 16 bits.
允许这些编码表示辅助平面代码点,其值太大,无法容纳16位。
A pair of 16-bit code points — the first from the high surrogate area (D800–DBFF),and the second from the low surrogate area (DC00–DFFF) — are combined to form a 32-bit code point from the supplementary planes.
一对16位代码点 - 第一个来自高代理区域(D800-DBFF),和来自低代理区域(DC00-DFFF)的第二个组合以从辅助平面形成32位代码点。
Unicode and ISO/IEC 10646 do not assign actual characters to any of the code points in the D800–DFFF range — these code points only have meaning when usedin surrogate pairs.
Unicode和ISO / IEC 10646不向D800-DFFF范围中的任何代码点分配实际字符 - 这些代码点仅在使用时才有意义在替代对。
Hence an individual code point from a surrogate pair does not represent a character, is invalid unless used in a surrogate pair, and is unconditionally invalid in UTF-32 and UTF-8 (if strict conformance to the standard is applied).
因此,来自代理对的单个代码点不表示字符,除非在代理对中使用,否则是无效的,并且是无条件无效的UTF-32和UTF-8(如果严格遵守标准)。
字符按照UTF-16进行编码的规则是: - 字符的值小于0x10000的用等于该值的16位整数来表示。 - 字符的值介于0x10000和0x10FFFF之间的,用一个值介于0xD800和0xDBFF(在所谓的高8位区)的16位整数和值介于0xDC00和0xDFFF(在所谓的低8位区)的16位整数来表示。 - 字符的值大于0x10FFFF不能按照UTF-16进行编码。注意:在0xD800和0xDFFF间的值是特别为UTF-16预留,所以不应该将任何字符的值指定为这个区间内的数值。
D800-DB7F High Surrogates 高位替代 895
DB80-DBFF High Private Use Surrogates 高位专用替代 127
DC00-DFFF Low Surrogates 低位替代 1023
高位替代就是指这个范围的码位是两个WORD的UTF-16编码的第一个WORD。低位替代就是指这个范围的码位是两个WORD的UTF-16编码的第二个WORD。那么,高位专用替代是什么意思?我们来解答这个问题,顺便看看怎么由UTF-16编码推导Unicode编码。
如果一个字符的UTF-16编码的第一个WORD在0xDB80到0xDBFF之间,那么它的Unicode编码在什么范围内?我们知道第二个WORD的取值范围是0xDC00-0xDFFF,所以这个字符的UTF-16编码范围应该是0xDB80 0xDC00到0xDBFF 0xDFFF。我们将这个范围写成二进制:
1101101110000000 11011100 00000000 - 1101101111111111 1101111111111111
按照编码的相反步骤,取出高低WORD的后10位,并拼在一起,得到
1110 0000 0000 0000 0000 - 1111 1111 1111 1111 1111
即0xe0000-0xfffff,按照编码的相反步骤再加上0x10000,得到0xf0000-0x10ffff。这就是UTF-16编码的第一个WORD在0xdb80到0xdbff之间的Unicode编码范围,即平面15和平面16。因为Unicode标准将平面15和平面16都作为专用区,所以0xDB80到0xDBFF之间的保留码位被称作高位专用替代。
————————————————
版权声明:本文为CSDN博主「Lobxxx」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xinbaobaoer/article/details/56290210
网友评论