頁碼字元編碼的別名,也稱代碼,是特定語言的字元集的一張表。

歷史

早期,頁碼是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"。

 
頁碼437

隨著圖形化使用者介面作業系統的廣泛使用(最初被廣為接受的是Windows 3.1),作業系統具有了字元繪製的功能。微軟在Windows作業系統沒有轉向UTF-16作為內碼實現之前(也就是在Windows 2000之前),針對不同的使用地區與國家,定義了一系列的支援不同語言字元集的頁碼,被稱作"Windows(或ANSI)頁碼"。代表性的是實現了ISO-8859-1的頁碼1252

OEM(IBM PC)代碼頁

頁碼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的緣由。

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]);
 }
}

外部連結