确定Windows XP到底是UCS-2的还是UTF-16的

一般认为Windows下以16bit表示的Unicode并不是UTF-16,而是UCS-2。UCS-2是一种编码格式,同时也是指以一一对应关系的Unicode实现。在UCS-2中只能表示U+0000到U+FFFF的BMP(Basic Multilingual Plane ) Unicode编码范围,属于定长的Unicode实现,而UTF-16是变长的,类似于UTF-8的实现,但是由于其字节长度的增加,所以BMP部分也做到了一一对应,但是其通过两个双字节的组合可以做到表示全部Unicode,表示范围从U+0000 到 U+10FFFF。关于这一点,我在很多地方都看到混淆了,混的我自己都有点不太肯定自己的说法了,还好在《UTF-16/UCS-2》中还是区别开了,不然我不知道从哪里去寻找一个正确答案。(哪怕在IBM的相关网页上都将UCS-2作为UTF-16的别名列出)

《UTF-16/UCS-2》文中有以下内容:

UTF-16 is the native internal representation of text in the Microsoft Windows 2000/XP/2003/Vista/CE; Qualcomm BREW operating systems; the Java and .NET bytecode environments; Mac OS X's Cocoa and Core Foundation frameworks; and the Qt cross-platform graphical widget toolkit.[1][2][citation needed]

Symbian OS used in Nokia S60 handsets and Sony Ericsson UIQ handsets uses UCS-2.

The Joliet file system, used in CD-ROM media, encodes filenames using UCS-2BE (up to 64 Unicode characters per file).

Older Windows NT systems (prior to Windows 2000) only support UCS-2.[3]. In Windows XP, no code point above U+FFFF is included in any font delivered with Windows for European languages, possibly with Chinese Windows versions.[clarification needed]

很明确的说明了Windows 2000以后内核已经是UTF-16的了,这点还真是与平时的感觉相违背,于是可以测试一下。在UTF-16的编码转换函数(Python实现)

中我在windows下输出了三个太玄经的字符,“”不过实际实在UltraEdit中输出的,虽然在windows下的确是显示出来了,但是也可能是UltraEdit的功能,我们这次用windowsAPI显示出来,以此证明,Windows的内核的确是能够识别并显示此三个太玄经的字符。至于为什么能显示太玄经的字符就表示内核是UTF-16的,是因为UCS-2只能表示到BMP范围的字符,太玄经的字符超出了其能表示的范围,假如你有古老电脑的,安装着Windows NT早期版本的系统,可以用同样的例子试试,应该是不能显示出来的。

int _tmain(int argc, _TCHAR* argv[])

{

wchar_t lwc[8];

lwc[0] = 0xd834;

lwc[1] = 0xdf00;

lwc[2] = 0xd834;

lwc[3] = 0xdf01;

lwc[4] = 0xd834;

lwc[5] = 0xdf02;

lwc[6] = 0;

lwc[7] = 0;

MessageBoxW(NULL, lwc, lwc, MB_OK);

return 0;

}

会弹出一个对话框,显示字符。很显然,Windows内核是能正确识别UTF-16字符了。

但是为什么平时都说Windows是UCS-2的呢?因为其编程的接口都是UCS-2的,根本不能理解超出UCS-2但是确是UTF-16的字符,比如上述的太玄经字符。在上面的例子中,其实只有3个字符,显示的时候也能正确,但是看下面的例子:

int _tmain(int argc, _TCHAR* argv[])

{

wchar_t lwc[8];

lwc[0] = 0xd834;

lwc[1] = 0xdf00;

lwc[2] = 0xd834;

lwc[3] = 0xdf01;

lwc[4] = 0xd834;

lwc[5] = 0xdf02;

lwc[6] = 0;

lwc[7] = 0;

int i = wcslen(lwc);

printf("%d\n", i);

int j = lstrlenW(lwc);

printf("%d\n", j);

return 0;

}

无论是i,j都是6,也就是说,无论是Windows下的C语言库函数(wcslen),还是其API(lstrlenW是windows的API,这点不要奇怪),都是无法正确识别UTF-16字符的,连数数都不会数,所以实际的编程体验就是,虽然其内核UTF-16化了,但是你还是只能当UCS-2来使用-_-!

以上测试也许还不能完全让人信服,再看看MFC的例子(VS2005下的MFC版本)

老地方 http://groups.google.com/group/jiutianfile/

有一个TestUnicodeMFc.rar的工程,打开看看,就知道了。当太玄经的3个字符在输入框中时,通过CEdit控件计算出来的长度是6,最最与以前多字节的时候想的是,当你删除一个字符(按一下backspace),你删除的不是一个太玄经字符,而是删除了最后一个字符的一半,然后最后一个字符虽然消失了,但是你发现还有其一半的存在,然后计算长度,输出的是5。唯一比以前好的是,没有出现乱码,原因在于,这个单个的UTF-16字符已经超过了UCS-2能表示的范围,所以没有意义。

至此,我的结论是,Windows是已经从内核支持UTF-16了,但是你还是得在UCS-2上编程-_-!

关于此部分内容参看《UTF-16/UCS-2》

关于Unicode的编码范围的内容参看《Mapping of Unicode character planes》

posted on 2011-02-14 11:39  katago  阅读(1513)  评论(1编辑  收藏  举报