神奇的「叱る」
神奇的「叱る」
最近在项目中遇到了一个关于编码问题相关的BUG。现总结如下:
关键字
- サロゲートペア文字
- Surrogate
环境
- AP:Windows 2000
- 语言:Java
BUG现象
先说一下背景吧,从题目上大家可能也已经明白了,这个系统是一个日文系统的软件。 如果你用日文系统的话,可以试着打一下「しかる」在选择汉字的时候,有一组环境依存的选项。里面的「叱」字变成了乱码。这就是问题的起因。 客户就选择了那个乱码的字。好像在其它系统里是正常的。不过读到我们系统的时候就出问题了。其实这个文字变成乱码这个问题是和系统相关,我们也没有办法。但是问题是乱码的部分被系统解析成两个字符了。就是是str.length=2而不是1,所以我们系统中所有的字符串的长度检测全都出问题了。
BUG解析
查了一些日文网站,说这个字好像还和系统的编码表相关,windows visita以后的系统就不会显示乱码了。这个可能还和Unicode5.0编码表相关。 通过研究知道了一些以前没有注意的技术细节,关于代码单元长度和点数的区别。
BUG解决
使用codePointCount就可以得到正确的值。 str.codePointCount(0, str.length())
总结
以前还真不知道codePointCount这组函数,从网上找了段总结,放在下边了。
一般不需要考虑代码单元的长度值,可以简单地认为其与代码点的长度是一样的。 只有增补字符,即代码点为U+10000 - U+10FFFF的字符,这是Unicode5.0中新增的代码点字符。 在Java中一个Unicode字符是使用UTF-16编码的char进行表示的,也就是一个char只能表示U+0000 - U+DFFF的Unicode基本字符(BMP)。因此在Java中需要表示U+10000 - U+10FFFF的的字符需要使用一对代码字符进行表示,高代理字符的范围为U+D800 - U+DBFF,低代理字符的范围为U+DC00 - U+DFFF。比如表示U+10400的字符需要两个char(U+D801,U+DC00)才能表示,这时代码点长度为1。而代码单元长度为2。
参考文献
1.http://itpro.nikkeibp.co.jp/article/COLUMN/20091209/341831
2.http://d.hatena.ne.jp/okazuki/20070512/1178979536
3.http://www.ibm.com/developerworks.cn/java/j-unicode/