by chad, 2011年5月2日
Unicode UTF-8 GBK这些不同的编码,我们可以想象为不同的字典。同一个汉字,在不同的字典里面,我们用不同的编号保存。比如汉字"陈"在Unicode里编号为9648,在GBK里面是0xB3C2,在UTF-8中呢就是0xE99988. 大家可以通过"附件->系统工具->编码映射表"查找" 陈"这个字的编码,可以得到它的Unicode编码及GBK的编码。UTF-8的生成依赖于对应字符的Unicode编码。规则如下:
Unicode |
UTF-8 |
说明 |
0000 - 007F |
0xxxxxxx |
对于这个范围的Unicode,UTF-8编码也用一个字节来表示 |
0080 - 07FF |
110xxxxx 10xxxxxx |
对于这个范围的Unicode,UTF-8编码也用两个字节来表示。在第一个字节前加上110,在后一个节里加上10 |
0800 - FFFF |
1110xxxx 10xxxxxx 10xxxxxx |
对于这个范围的Unicode,UTF-8编码也用两个字节来表示。在第一个字节前加上110,在后两个节里加上10 |
"陈"字落在第三个区间,它的utf-8编码需要用三个字节表示,具体转换过程如下:
① 9648的二进制编码如下 1001011001001000
② 将它分成4-6-6三段分别是 1001 011001 001000
③ 分别在前面加上1110 10 10 变成如下:11101001 10011001 10001000
在Java当中我们可以通过如下方法输出"陈"这个字:
1) System.out.println("/u9648");
2) byte[] bs = new byte[]{(byte)179,(byte)194};
System.out.println(new String(bs,"GBK"));
注:179是B3的十进制,194是C2的十进制
3) byte[] bs = new byte[]{(byte)233,(byte)153,(byte)136};
System.out.println(new String(bs,"utf-8"));
注:数组里的值就是上面utf-8二制值对应的十进制值
233 - 11101001, 153 - 10011001, 136 - 10001000
反过来我们看下面的代码:
System.out.println("陈".getBytes("GBK").length);
System.out.println("陈".getBytes("UTF-8").length);
打印出来的值分别是2,3
关于编码的很有意思的是例子就是在一个新建的文本文件里面输入"联通"两个字,结果却不能正确显示。这是因为缺省系统文本文件用的是GBK编码输入,而联通的GBK编码如下:
文字 |
十六进制 |
二进制 |
说明 |
联 |
0xC1AA |
11000001 10101010 |
由于它的两个字节由110 和10开头,所以双击打开的时候,把内容的GBK编码认成了UTF-8编码,所以把它当成 00001 101010 这个Unicode编码所代码的文字,这个字符的Unicode值为 /u006A,它就是字符J |
通 |
0xCDA8 |
11001101 10101000 |
这个转换成UTF-8后,没有对应的字符存在,所以最终文档没办法正确显示 |