1. 程式人生 > >C++11 之字符集

C++11 之字符集

  1. 基礎概念理解

     1)通常我們將一個標準中能夠表示所有字元的一個集合稱為字符集,如Unicode字符集。

     2)在字符集中每個字元佔用一個唯一的碼位。如Unicode就有1114112個字元碼使用0x0~0x10FFFF的16進位制數唯一表示每一個 字元。

      3)由於計算機中通常時以位元組為單位進行儲存的,因此就要有一種編碼方式對字元碼位進行編碼儲存。如:基於Unicode字集的編碼方式有:UTF-8(1-6個位元組變長編碼方式表示Unicode)、UTF-16、UTF-32。

     4)其它字符集ASCII、GB2312(簡體中文及器相關符號,基於區位碼編碼方式),BIG5(繁體中文及其相關字元。2個位元組表示一個漢字)

     5)ASCII以7個二進位制為進行表示128個字元,因此其也可以理解為一種編碼方式。

     6)不同的編碼方式對於相同二進位制字符集的解釋結果時不同的,這就是網頁有時候按不同編碼方式顯示會出現亂碼的原因。

    7)由於眾多的字符集帶來的麻煩,因此ISO/Unicode兩個組織聯合釋出了Unicode字符集,Unicode字符集仍然再發展中,因此過多種字符集及編碼方式共存的情況在相當長的一段時間內仍然會存在。基礎概念理解

  2. C++11對於Unicode支援的改進

     1)C++98標準中,定義了wchar_t來支援“Unicode”,由於wchar_t太寬容了,導致成員寫的wcht_t的移植性不好。因為C++98 標準中wchar_t的寬度由編譯器決定,這就出現了wchar_t通常在windows上被實現為16位寬,而Linux下實現為32位寬的情況發生。

    2)UTF_8 1~6個位元組的變長編碼,UTF-16 2個位元組定長編碼, UTF-32  4個子節的定長編碼。

    3)系統上能否正常考到Unicode字元受:原始檔的儲存格式、編譯器設定的編碼格式、輸出裝置支援的編碼型別。 C++11在語言層面上支援Unicode,由於Linux系統下shell、vi、g++等都依賴locale設定而採用UTF-8編碼,因此UTF-16,UTF-32編碼的字元不能正常顯示。

  3. C++的編碼轉換 

     1)C++11說是ucchar標頭檔案中有c16rttomb、 mbrttoc16、c32rttomb、mbrttoc32 等四個字元編碼轉換函式,但是嘗試了下,沒有這個標頭檔案及函式。

    2)C++對編碼轉換新方法都源於C++的locale機制支援,locale描述的是一些必需知道的區域特徵,如:程式執行的國家/地區的數字符號、日期表示、錢幣符號等。通常知道了一個地區的locale,要使用不同的地區特徵,則需要訪問該locale的一個facet。 facet可以理解為locale的一些介面,比如:num_put/num_get、money_put/money_get、codecvt等。                            

     3) codecvt是一個模板類,實現從當前locale下的多字元編碼字串到多種Unicode編碼轉換的一個facet。每種facet負責不同型別的編碼資料轉換,現行編譯支援的情況下,一種locale並不能支援所有的codecvt facet。程式設計師可以通過has_facet檢視locale在本機的支援情況。例如:

    #inlude <locale>  
    #include <iostream>    
    using namespace std;

    int mian
    {
        //定義一個locale
        locale loc("en_US.UTF-8");
        
        //判斷loc的facet的支援情況
        if (!has_facet<codecvt<wchar_t, char, mbstate_t>>(lc))
        {
            cout << "Do not support muti char to wchar_t facet" << endl;
        } 
        
        if (!has_facet<codecvt<char, char, mbstate_t>>(lc))
        {
            cout << "Do not support muti char to char facet" << endl;
        }
     
        if (!has_facet<codecvt<char16_t, char, mbstate_t>>(lc))
        {
            cout << "Do not support utf-16 to utf-8 facet" << endl;
        }


        if (!has_facet<codecvt<char32_t, char, mbstate_t>>(lc))
        {
            cout << "Do not support utf-32 to utf-8 facet" << endl;
        }
        return 0;
    }