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

歷史

早期,代碼頁是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]);
 }
}

外部連結