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后,没有对应的字符存在,所以最终文档没办法正确显示 |