頁碼
歷史
早期,頁碼是IBM稱呼電腦的BIOS所支援的字元集編碼。當時通用的作業系統都是命令列介面,這些作業系統直接使用BIOS提供的字元繪製功能來顯示字元(或者是一組嵌入在顯示卡字元產生器中的字形)。這些BIOS頁碼也被稱為OEM頁碼。圖形作業系統使用自己的字元呈現引擎(rendering engine),可以支援多個不同的字元集編碼,這類頁碼被稱作ANSI頁碼。
早期IBM和微軟內部使用數字來標記不同的編碼字元集,不同的廠商對同一個字元集編碼使用各自不同的名稱。例如,UTF-8在IBM稱作頁碼1208,在微軟稱作頁碼65001,在SAP稱作頁碼4110。
1987年4月,IBM發佈了PC-DOS 3.3,正式開始使用16位元的無符號整數標識不同的頁碼。這時的PC機使用CGA顯示系統的字元介面,繪製不同語言的字元依靠BIOS硬件廠商(在當時就是指制定業界標準的IBM)提供的功能。如果想更換所支援的字元集,就必須換上支援該字元集的ROM晶片。微軟作為DOS作業系統的軟件廠商,並不擁有繪製這些字元集的知識產權。所以這些字元集的繪製實現,稱作OEM頁碼。最常見、最具代表性的OEM頁碼是"IBM PC或MS-DOS 頁碼437"。
隨着圖形化使用者介面作業系統的廣泛使用(最初被廣為接受的是Windows 3.1),作業系統具有了字元繪製的功能。微軟在Windows作業系統沒有轉向UTF-16作為內碼實現之前(也就是在Windows 2000之前),針對不同的使用地區與國家,定義了一系列的支援不同語言字元集的頁碼,被稱作"Windows(或ANSI)頁碼"。代表性的是實現了ISO-8859-1的頁碼1252。
OEM(IBM PC)代碼頁
- 437—最初的IBM PC代碼頁,實現了擴充ASCII字元集
- 737—希臘語
- 850—「多語言(Latin-1)」(西歐語言)
- 852—「斯拉夫(Latin-2)」(中歐及東歐語言)
- 855—西里爾(Cyril)字母
- 857—土耳其語
- 858—帶歐元符號的「多語言」
- 860—葡萄牙語
- 861—冰島語
- 863—法語加拿大英語
- 865—北歐
- 866—西里爾(Cyril)字母
- 869—希臘語
頁碼819實現了Latin-1(ISO/IEC 8859-1),用於IBM AS/400小型機。
OEM頁碼轉換為ASCII頁碼
對於中日韓的多位元組編碼的頁碼,OEM頁碼與ASCII頁碼相同,例如對於簡體中文的OEM頁碼與ASCII頁碼就是GBK頁碼。而對於單位元組編碼的頁碼,如英語、俄語等,OEM頁碼與ASCII頁碼一般不同。這是因為在MS-DOS時代,電腦只能使用字元介面在螢幕上畫出表格的框線,所以OEM頁碼要在單位元組字元集中包含方框繪製字元;此外,OEM頁碼437提供的有限的變音符號,只能覆蓋法語、西班牙語、德語、意大利語、瑞典語的字母表。而在Windows的早期時代,仍然使用單位元組字元集,這時就捨棄了這些不必要的方框繪製字元,取而代之的是丹麥語、挪威語、冰島語、加拿大法語的變音符號。為此,一個用OEM頁碼的位元組流要在Windows上正確顯示,就需要或者顯式設定使用OEM頁碼;或者要顯式把OEM頁碼的位元組流轉化為ASCII頁碼的字元流,這需要使用Windows系統呼叫OemToChar()
。
Windows(ANSI)代碼頁
Windows頁碼最初是根據ANSI草案實現的,這個草案最終成為ISO 8859-1。這是Windows頁碼被稱作ANSI的緣由。
- 874—泰文字母
- 1250—東歐拉丁字母
- 1251—古斯拉夫語
- 1252—西歐拉丁字母ISO-8859-1.
- 1253—希臘語
- 1254—土耳其語
- 1255—希伯來語
- 1256—阿拉伯語
- 1257—巴爾
- 1258—越南
Windows-1252與ISO-8859-1並不完全一致。ISO-8859-1在0x80-0x9F範圍的控制字元,在Windows-1252中被可列印字元取代。由於在web網頁中,ASCII控制字元不起作用,所以網頁一般用Windows-1252頁碼標記替代ISO-8859-1標記。
中日韓語言頁碼
既是OEM頁碼,也是Windows頁碼。
- 936—簡體中文(GBK)
- 950—繁體中文(大五碼)
- 932—日文(Shift_JIS)
- 949—韓文(EUC-KR)
- 20000(CNS)以EUC編碼的繁體中文CNS編碼
- 20002(Eten)以EUC編碼的繁體中文倚天碼
- 20936(GB2312-80)以EUC編碼的簡體中文GB2312編碼(老裝置或嵌入式裝置常見)
- 50227(ISO-2022-GB)簡體中文的Esc序列編碼,純ASCII
- 50229(ISO-2022-CNS)繁體中文的Esc序列編碼,純ASCII
- 52936(HZ-GB-2312)以~{和~}分隔的簡體中文GB2312編碼,純ASCII
- 54936—簡體中文(GB18030)
其他代碼頁
Windows作業系統中使用的頁碼
Windows平台上的GUI程式使用ANSI頁碼,而在控制台程式使用OEM頁碼(以便向下相容)。這意味着,如果在記事本程式(notepad.exe)打開一個8位元字元集編碼的文字檔案,將使用ANSI頁碼;如果在命令列中用type命令顯示這個文字檔案的內容,將使用OEM頁碼。這兩個頁碼在前128個字元的編碼是一樣的,但後128個字元的編碼可能不一致。在Windows的命令列窗口通過標記、複製操作把一部分文字內容複製到記事本程式中,實際上是把Unicode格式的內容儲存在剪貼簿,使得這種文字複製保持了字元編碼的透明轉換。
對於Windows作業系統中的命令列窗口(Command Prompt),chcp命令在沒有參數時,顯示當前頁碼;chcp命令帶一個整數參數,則改變命令列窗口的當前頁碼為參數所指定。
把UTF-8編碼文字直接寫到控制台,必須先使用函數SetConsoleOutputCP(65001),然後使用puts一族的函數來輸出文字。把UTF-8編碼文字寫入UTF-8檔案時,可以直接使用窄字元輸出函數。
在Windows API中,CP_ACP與CP_OEMCP分別表示當前系統的ANSI頁碼與OEM頁碼。對於CJK(多位元組編碼)的環境(泰文,日文,韓文,中文),CP_ACP與CP_OEMCP沒有區別。對於非 CJK(單位元組編碼)的環境這兩個頁碼不同。 Windows的檔案操作的API預設使用ASCII頁碼(即CP_ACP),裝置的操作的函數使用OEM頁碼(即CP_OEMCP)。讀寫console的函數是對console裝置的操作,所以預設使用OEMCP。
查詢頁碼的資訊
Windows系統呼叫GetCPInfo()
給出指定的頁碼的資訊。如東亞多位元組頁碼的預設字元、前導位元組的範圍:
{
CPINFO info;
UINT iCP = 932; //GBK
GetCPInfo(iCP, &info);
printf("Code page %d's default char is [%c]\n", iCP, info.DefaultChar[0]);
printf("Max size of a char: %d\n", info.MaxCharSize);
int i;
const int iMaxLeadBytePairNum = 5;
for (i = 0; i < iMaxLeadBytePairNum; i++)
{
if (info.LeadByte[i * 2] == 0 && info.LeadByte[i * 2 + 1] == 0)
break;
printf("Lead byte pair %d: 0x%02X-0x%02X\n", i, info.LeadByte[i * 2], info.LeadByte[i * 2 + 1]);
}
}
外部連結
- IBM代碼頁(英文)
- IBM/ICU Charset Information
- Microsoft code page identifiers(Microsoft's list contains only code pages actively used by normal apps on Windows see also Torsten Mohrin's list for the full list of supported code pages)
- Shorter Microsoft list containing only the ANSI and OEM code pages but with links to more detail on each
- Character Sets And Code Pages At The Push Of A Button(頁面存檔備份,存於互聯網檔案館)