1. 程式人生 > >程式碼實現之查詢內碼表的資訊(附加:關於系統區域設定的說明)

程式碼實現之查詢內碼表的資訊(附加:關於系統區域設定的說明)

Windows作業系統中使用的內碼表

Windows平臺上的GUI程式使用ANSI內碼表,而在控制檯程式使用OEM內碼表(以便向後相容)。這意味著,如果在記事本程式(notepad.exe)開啟一個8位字符集編碼的文字檔案,將使用ANSI內碼表;如果在命令列中用type命令顯示這個文字檔案的內容,將使用OEM內碼表。這兩個內碼表在前128個字元的編碼是一樣的,但後128個字元的編碼可能不一致。在Windows的命令列視窗通過標記、複製操作把一部分文字內容複製到記事本程式中,實際上是把Unicode格式的內容儲存在剪貼簿,使得這種文字複製保持了字元編碼的透明轉換。也就是說,在Windows的命令列視窗通過標記、複製操作把一部分文字內容複製到記事本程式

就是先將Windows的命令列視窗複製過來的以多位元組字符集編碼的字元轉換為該字元的Unicode字符集編碼(由於現在的Windows版本本身是Unicode編碼的版本)並將該字元的Unicode字符集編碼儲存在剪貼簿,最後記事本程式再將儲存在剪貼簿該字元的Unicode字符集編碼(值)轉換為記事本自己所用的多位元組字符集的編碼值。這裡,Unicode字符集做了兩個多位元組字符集的編碼值轉換的中介,因為Unicode字符集可以和任意多位元組字符集相互轉換。這裡兩個多位元組字符集間的編碼值轉換前提是轉化它們都有的字元。

對於Windows作業系統中的命令列視窗(Command Prompt),chcp命令在沒有引數時,顯示當前內碼表(指的是OEM內碼表,而不是ANSI內碼表即Windows內碼表)

;chcp命令帶一個整數引數,則改變命令列視窗的當前內碼表為引數所指定。

查詢內碼表的資訊

Windows系統呼叫GetCPInfo()給出指定的內碼表的資訊。如東亞多位元組內碼表的預設字元、前導位元組的範圍:

#include <windows.h>
{
 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]); } }

附加:

現在的Windows作業系統(即一款軟體)已經是用Unicode 字符集重新修改過原始碼編譯而得的,即Windows作業系統自身那些元件或是自帶程式執行的介面上顯示的字元都是用Unicode 字符集編碼的。也就是說,Windows早期(至少是95年以前的事情了)是ANSI字符集的。後來,Windows支援了Unicode,但當時大部分軟體都是用ANSI編碼的,unicode還不流行,怎麼辦?Windows想了個辦法,就是允許一個預設語言編碼,就是當遇到一個字串,不是unicode的時候,就用預設語言編碼解釋。(在區域和語言選項裡可以改預設語言)

這個預設語言,在不同Windows語言版本里是不同的,在簡體中文版裡,是GBK,在繁體中文版裡,是BIG5,在日文版裡是JIS。

所謂系統區域設定,就是說設定要在什麼地區或是國家的語言環境下執行該作業系統上的非 Unicode 程式。那麼,如何在系統區域設定中選擇哪一個項呢?這個就要看你執行的非 Unicode 程式裡使用的字串是用啥編碼的。比如,你的非 Unicode 程式裡使用的字串是希臘語(這個語言)的字元,那在系統區域設定中選擇希臘語(希臘)。再比如,你的非 Unicode 程式裡使用的字串是中文漢語(這個語言)的字元,但是我們發現在系統區域設定中有多個關於中文的選項,這是因為使用中文的有多個地區,不同地區都有各自中文字符集,所以你還要知道你的非 Unicode 程式裡使用的字串是來自哪個地區的中文漢語(這個語言)的字元,才能確定在系統區域設定中的選項。那你就會有疑問了:每個地區裡的中文字符集也是有好多個的呀?是的,所以例如你在在系統區域設定中選擇中文(簡體,中國)時,系統預設是使用GBK這個中文字符集的。當然,這裡說的預設字符集要分兩邊說,因為Windows平臺上的GUI程式使用ANSI內碼表,而在控制檯程式使用OEM內碼表(以便向後相容)。所以,例如,你在系統區域設定中選擇希臘語(希臘)時,Windows平臺上的GUI程式預設使用的ANSI內碼表是1253希臘語,而在控制檯程式預設使用的OEM內碼表是737—希臘語,即Windows平臺上的GUI程式和控制檯程式分別預設使用的是希臘語的兩個不同字符集。該例子具體如下圖所示:

你在系統區域設定中選擇希臘語(希臘)時,在控制檯程式預設使用的OEM內碼表是737—希臘語:



同時,這幅圖也說明對於Windows作業系統中的命令列視窗(Command Prompt),chcp命令在沒有引數時,顯示當前內碼表指的是OEM內碼表,而不是ANSI內碼表即Windows內碼表。

==============================

控制檯程式使用OEM內碼表,如下圖所示:



一個是OEM 437,一個是OEM 936。這裡要說明的是中日韓語言內碼表既是OEM內碼表,也是Windows內碼表。

中日韓語言內碼表

既是OEM內碼表,也是Windows內碼表。

=================================================

更改系統區域設定

系統區域設定可確定用於在不使用 Unicode 的程式中輸入和顯示資訊的預設字符集(字母、符號和數字)和字型

這可讓非 Unicode 程式在使用指定語言的計算機上執行。在計算機上安裝其他顯示語言時,可能需要更改預設系統區域設定。為系統區域設定選擇不同的語言並不會影響Windows 或其他使用 Unicode 的程式的選單和對話方塊中的語言。

  1. 單擊“管理”選項卡,然後在“非 Unicode 程式的語言”下單擊“更改系統區域設定”如果系統提示您輸入管理員密碼或進行確認,請鍵入該密碼或提供確認。

  2. 選擇語言,然後單擊“確定”

    若要重新啟動計算機,請單擊“立即重新啟動”

==================================

再來研究Windows的記事本。

Windows早期(至少是95年以前的事情了)是ANSI字符集的,也就是說一箇中文文字,在Windows簡體中文版顯示的是中文,到Windows日文版顯示的就不知道是什麼東西了。

後來,Windows支援了Unicode,但當時大部分軟體都是用ANSI編碼的,unicode還不流行,怎麼辦?Windows想了個辦法,就是允許一個預設語言編碼,就是當遇到一個字串,不是unicode的時候,就用預設語言編碼解釋。(在區域和語言選項裡可以改預設語言)

這個預設語言,在不同Windows語言版本里是不同的,在簡體中文版裡,是GBK,在繁體中文版裡,是BIG5,在日文版裡是JIS

而記事本的ANSI編碼,就是這種預設編碼,所以,一箇中文文字,用ANSI編碼儲存,在中文版裡編碼是GBK模式儲存的時候,到繁體中文版裡,用BIG5讀取,就全亂套了。

記事本也不甘心這樣,所以它要支援Unicode,但是有一個問題,一段二進位制編碼,如何確定它是GBK還是BIG5還是UTF-16/UTF-8?記事本的做法是在TXT檔案的最前面儲存一個標籤,如果記事本開啟一個TXT,發現這個標籤,就說明是unicode。標籤叫BOM,如果是0xFF 0xFE,是UTF16LE,如果是0xFE 0xFF則UTF16BE,如果是0xEF 0xBB 0xBF,則是UTF-8。如果沒有這三個東西,那麼就是ANSI,使用作業系統的預設語言編碼來解釋。

Unicode的好處就是,不論你的TXT放到什麼語言版本的Windows上,都能正常顯示。而ANSI編碼則不能。(UTF-8的好處是在網路環境下,比較節約流量,畢竟網路裡英文的資料還是最多的)

舉例:

同樣一段中文文字(可以插入一些英文),儲存成ANSI/Unicode/UTF-8,三個檔案。

修改windows的預設語言為日語之類的(WIN7的改法是:控制面板-時鐘、語言和區域-更改顯示語言-區域和語言-管理-非unicode程式語言-更改區域設定/WNIXP改法是:控制面板-區域和語言選項-非unicode程式語言)。

修改完要求重啟,重啟以後,再開啟這三個檔案,ANSI的編碼全亂了,其餘兩個都正常顯示,這就是UNICODE的作用。

另外,為什麼記事本、開始選單什麼的還是正確的中文呢?明明我已經改了預設語言了?因為它們的程式編碼也是unicode的。

要把txt發給國外的朋友或者用在非中文的作業系統/軟體裡,那麼你的編碼最好選擇unicode