一般認為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》。