utf-8编码研学

好久好久没有更新博客了。登录密码都是输了四五遍才输对。

最近写了挺多邮件。相对的,好像某处倾泻掉了一样,就没心情在博客上码字了。于是今天依旧是灌水的短篇吧。

最近被utf-8搞得各种头痛。差点就要练出肉眼看二进制编码的火眼金睛。先举个今天遇到的小问题吧。
java用gbk方式写入的文件,似乎有个特性,是会自动把gbk编码中不能识别的0x0这个字节,替换成”?”,也即0x3F。这原本也没什么,但当他读取utf8文本并重新写入新的文件的时候,就会出现偏差。
众所周知,utf8编码的英文和符号部分是同ASCII编码兼容的。同时,在大多数中文中,很少出现0x0这样的字节。因此,用ASCII硬写utf8编码的中英混合文字,然后这个文件再用utf8的方式打开,运气好的话居然可以侥幸蒙混过关,毫无错误。然而,一旦文字中出现了带有0x0字节的utf8编码,就没那么侥幸了。
例如“个性”的性字,其unicode编码为0x6027, 翻译成utf8的话:

性
 60	    27
 01100000   00100111
[1110]0110 [10]000000 [10]100111
 E6	    80	       A7

这里用方括号标识了utf8的字节头,方便辨识。在windows上是使用小端序,所以实际的序列会是这样:

0110 1110 0000 1000 0111 1010

这里第三个字节出现了0x0,悲剧发生了,被java的流输出不知怎么就那么智能替换成了”?”

0110 1110 1111 0011 ...
6    E    F    3

结果这里就乱码了。打出来内容一团糟。变成“个<E6>?”。

另外一个曾让我头疼一天的问题,就是根据utf8编码规则,并不会出现0xC0 0x80这个双字。因为如果按照编码规范

 0xC0           0x80
[110]0 0000    [10]00 0000
 0000           0000

这根本就是0x0嘛!不可能编码成这个样子的。wiki上查了半天才发现,原来这个又是windows的专有解决方案。完全是windows系统一厢情愿,想要区别于一般的ASCII文本而作的别扭事。结果这样的文本想要插入到mysql数据库时,就会被数据库认为是不合理的utf8编码而被冷冷拒绝!
所以整理utf8的编码问题,有时候还是要一直看到二进制上面来,这样问题发生在哪里也就会比较清楚,该怎样解决就不再像是霰弹枪编程,左试右试都不知道哪里出错了哟。