Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的,但是在实际存储和传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。Unicode的实现方式称为Unicode转换格式(UnicodeTransformation Format,简称为UTF)。
对Unicode编码的主要有UTF-16BE、UTF-16LE、UTF-8、UTF-7以及UTF-32等实现方式,目前常用的实现方式是UTF-16LE、UTF-16BE和UTF-8。
UTF-16是用16bit编码来表达Unicode,这样表达范围是216(即65536),也就是UTF-16的代码单元(Code Unit)为16bits。如果表达BMP内的字符,用一个UTF-16的CodeUnit就可表达,对于辅助平面内的字符,UTF-16有巧妙的设计。
落在BMP内,从U+D800到U+DFFF之间的Code Point区段是永久保留不映射到字符, UTF-16利用这保留下来的0xD800-0xDFFF区段的CodePoint来对辅助平面内的字符的Code Point进行编码。
对U+0000.. U+D7FF以及U+E000.. U+FFFF的编码
UTF-16与UCS-2对这个范围内的CodePoint进行编码,采用单个16bit长的CodeUnit,数值等价于对应的Code Point。BMP中的这些Code Point是仅有的可以被UCS-2表示的Code Point。
对U+10000.. U+10FFFF的编码
辅助平面(Supplementary Planes)中的CodePoint,在UTF-16中被编码为一对16bit长的Code Unit(即32bit,4Bytes),称作代理对(surrogatepair)。
具体方法是:
这样,这个范围内的字符就被编码成了一个代理对[leadsurrogate,trail surrogate]:两个16bits的Code Unit,取值范围分别是0xD800..0xDBFF和0xDC00..0xDFFF。而BMP中得到的Code Unit的范围是0x0000..0xFFFF(0xD800..0xDFFF是保留的,不包含其中),所以这三个区段是相互不重叠的,在解码时很容易实 现。
UTF-16解码 |
||||
hi \ lo |
DC00 |
DC01 |
… |
DFFF |
D800 |
10000 |
10001 |
… |
103FF |
D801 |
10400 |
10401 |
… |
107FF |
⋮ |
⋮ |
⋮ |
⋱ |
⋮ |
DBFF |
10FC00 |
10FC01 |
… |
10FFFF |
下面以对U+64321的UTF-16编码为例,看一下对于辅助平面内的字符是如何编码的:
V = 0x64321 Vx = V - 0x10000 = 0x54321 = 01010100 0011 0010 0001 Vh = 01 0101 0000 // Vx 的高位部份的 10 bits Vl = 11 0010 0001 // Vx 的低位部份的 10 bits w1 = 0xD800 // 结果的前16位元初始值 w2 = 0xDC00 // 结果的后16位元初始值 w1 = w1 | Vh = 1101 1000 0000 0000 | 01 0101 0000 = 1101 1001 0101 0000 = 0xD950 w2 = w2 | Vl = 1101 1100 0000 0000 | 11 0010 0001 = 1101 1111 0010 0001 = 0xDF21
所以,这个字 U+64321 最终的 UTF-16 编码是:
0xD950 0xDF21
以下是据此而写的c++加码与解码的函数:
//unicode BMP之外字符 转换成UTF-16 加码函数 //DWORD v 为字符的UNICODE编码 编码值大于0XFFFF //WORD & w1 为转换成UTF-16后的 低位代理对 //WORD & w2 为转换成UTF-16后的 高位代理对 void EnCode(DWORD v,WORD &w1,WORD &w2) { DWORD vx=v-0x10000; WORD vh=(vx&0xFFC00)>>10; WORD vl=vx&0x03FF; w1=0xD800; w2=0xDC00; w1=w1|vh; w2=w2|vl; }
// UTF-16 转换成unicode编码的 解码函数 //DWORD v 为解码后的字符的UNICODE编码 编码值大于0XFFFF //WORD & w1 UTF-16的 低位代理对 //WORD & w2 UTF-16的 高位代理对 void DeCode(DWORD &w, WORD &w1, WORD &w2) { w1=w1&0x3FF; w2=w2&0x3FF; w=w1<<10; w=w|w2; w+=0x10000; }
应用举例:
(1)加码
WCHAR str[3]; //表示一个字符 memset(str,0,3*sizeof(WCHAR)); dw=0x64321; //该字符的unicode编码位于BMP之外 WORD w1,w2; EnCode(dw,w1,w2); str[0]=w1; str[1]=w2; str[3]=0;
(2)解码
DWORD dw=0; WORD w1,w2; w1=str[0]; w2=str[1]; //w2!=0 否则即为BMP之内的码 DeCode(dw,w1,w2); //dw 为UTF-16 所对应的unicode码值
参考资料:
http://blog.csdn.net/thl789/article/details/7506133