C++標準庫也提供了字符轉換的工具:ios
可是隻要要求能夠實現如下幾種轉換,須要注意的事這些都是針對std::codecvt的特例化版本.xcode
std::codecvt<char, char, std::mbstate_t> : 該版本的通常用於 UTF-8和ASCII(8bit)之間的轉換.函數
std::codecvt<char16_t, char, std::mbstate_t>: 該版本的通常用於 UTF-16和UTF-8之間的轉換.工具
std::codecvt<char32_t, char, std::mbstate_t>: 該版本的通常用於 UTF32和UTF-8之間的轉換.編碼
std::codecvt<wchar_t, char, std::mbstate_t>: 該版本的通常用於當前系統原生的wchar_t字符集和多字節字符集(multibyte characterset)之間的轉換.spa
std::codecvt是依賴std::locale的,若是你使用的當前標準庫有實現對對擴展字符集(Extented UNIX Code)的支持那麼咱們能夠很容易使用std::codecvt轉換進行 Unicode字符集和擴展字符集之間的轉換.指針
在此以前咱們須要瞭解一個 trivial-class:std::mbstate_t這個類很特殊,例如----採用multibyte編碼的時候,在這種狀況下在處理一個字符的時候,可能因爲「源緩衝區」已經空了,或者目標緩衝區滿了形成multibyte字符處理中斷。若是這種狀況出現將當前轉換狀態存儲到此類對象內.code
在瞭解std::codecvt以前咱們須要再明確一個概念:對象
源緩衝區: 存儲須要被轉換的字符的區域.繼承
目標緩衝區:存儲已經被轉換的字符的區域.
當從 wchar_t到char的時候:
會將每一個wchar_t切割爲 sizeof(wchar_t)個char對象.
當從char到wchar_t的時候:
會用sizeof(wchar_t)個char組裝成一個char.
所以不管是下面的in()操做仍是out()操做都只是切割或者組裝操做,並非到直接的把一個其餘字符集的字符映射到當前字符集(反之亦然).
其中有幾個函數返回值爲:
std::codecvt_base::ok 表示全部字符轉換成功.
std::codecvt_base::partial 並不是全部字符都轉換成功。
std::codecvt_base::error 遇到一個不能轉換的源字符.
std::codecvt_base::nocvt 無須轉換.
template<typename InternT, typename ExternT, typename State> class codecvt
構造函數:
explicit codecvt( std::size_t refs = 0 );
接受一個std::size_t類型的的數字,以當前數字做爲內存存儲std::codecvt的參考.
std::codecvt::out,do_out:
public: result out( StateT& state, const InternT* from, const InternT* from_end, const InternT*& from_next, ExternT* to, ExternT* to_end, ExternT*& to_next ) const; protected: virtual result do_out( StateT& state, const InternT* from, const InternT* from_end, const InternT*& from_next, ExternT* to, ExternT* to_end, ExternT*& to_next ) const;
須要注意的是: 都是經過std::codecvt::out來調用std::codecvt::do_out.
該函數的主要做用是將: 將外部表述轉爲內部表述(並非把外部字符集的字符轉爲內部字符集的對應字符).
from: const InternT*類型的指針,指向源緩衝區(此時是外部表述字符串)的開始.
from_end: const InternT*類型的指針,指向源緩衝區的結尾.
from_next: const InterT*&類型的指針,有可能須要被轉換的字符序列並不能所有轉換成功,所以該指針指向最後一個轉換成功的字符的位置.
to: const InternT*類型的指針,指向目標緩衝區(內部表述字符串)的開始位置.
to_end: const InternT*類型的指針,指向目標緩衝區的最後位置.
to_next: const InternT*&類型的指針,指向最後一個被存儲進來的字符的位置.
Demo:
#include <iostream> #include <fstream> #include <string> #include <locale> #include <iomanip> #include <codecvt> int main() { std::basic_string<char> u8Str{ u8"十" }; //utf8字符. std::basic_string<char> str{ "十" }; const std::codecvt<wchar_t, char, std::mbstate_t>& cvt = std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(std::locale()); std::basic_string<wchar_t> targetStr(u8Str.size() * 2, '\0'); std::mbstate_t state = std::mbstate_t{}; const char* internT = nullptr; wchar_t* externT = nullptr; for (const char& c : u8Str) { std::cout << std::hex << static_cast<unsigned short int>(c) << std::endl; } std::cout << std::endl; for (const char& c : str) { std::cout << std::hex << static_cast<unsigned short int>(c) << std::endl; } std::cout << std::endl; //將外部表述轉爲內部表述. cvt.in(state, &u8Str[0], &u8Str[u8Str.size()], internT, &targetStr[0], &targetStr[targetStr.size()], externT); for (const wchar_t& c : targetStr) { std::cout << std::hex << static_cast<unsigned short int>(c) << std::endl; } return 0; }
std::codecvt::int,do_in
public: result in( StateT& state, const ExternT* from, const ExternT* from_end, const ExternT*& from_next, InternT* to, InternT* to_end, InternT*& to_next ) const; protected: virtual result do_in( StateT& state, const ExternT* from, const ExternT* from_end, const ExternT*& from_next, InternT* to, InternT* to_end, InternT*& to_next ) const;
須要注意的是: 經過std::codecvt::out()調用std::codecvt::do_out()
該函數的主要功能是: 將外部表述轉爲內部表述.
剩下狀況都是跟std::codecvt::in()相反的.
std::codecvt::encoding,do_encoding
public: int encoding() const; protected: virtual int do_encoding() const;
獲取外部字符類型轉爲內部字符類型須要多少個內部字符.
std::codecvt::always_noconv,do_always_noconv
public: bool always_noconv() const; protected: virtual bool do_always_noconv() const;
若是未曾有過成功的轉換,返回true.
std::codecvt::length,do_length
public: int length( StateT& state, const ExternT* from, const ExternT* from_end, std::size_t max ) const; protected: virtual int do_length( StateT& state, const ExternT* from, const ExternT* from_end, std::size_t max ) const;
返回從外部字符轉爲內部字符的時候所須要消耗多少個內部字符.
max: 這個參數支出一個 外部字符 至關於 多少個內部字符. 好比一個w_char至關於2個char在vs2015的x86模式下.
std::codecvt::max_length,do_max_length
public: int max_length() const; protected: virtual int do_max_length() const;
返回 最多要多少個 外部字符 才能轉爲一個內部字符.
上面介紹的方法雖然能夠作到轉換(並非從一個字符集映射到另一個字符集),可是太過麻煩了。
所以標準庫又提供了更進一步的封裝,咱們在使用的時候須要#include<codecvt>
std::codecvt_utf8 : public std::codecvt(注意這裏的繼承)
template< class Elem, unsigned long Maxcode = 0x10ffff, std::codecvt_mode Mode = (std::codecvt_mode)0 > class codecvt_utf8 : public std::codecvt<Elem, char, std::mbstate_t>;
Elem: char16_t, char32_t, wchar_t.
Maxcode: Elem能表示的最大值.
Mode: 指出使用 Big-Endian 仍是 Little-Endian 還有讀寫的時候是否跳 BOM。(默認爲Big-Endian且不考慮BOM的).
主要目的: 用於 UTF8 和 UCS2/UCS4之間相互轉換.
std::codecvt_utf16 : public std::codecvt(繼承)
template< class Elem, unsigned long Maxcode = 0x10ffff, std::codecvt_mode Mode = (std::codecvt_mode)0 > class codecvt_utf16 : public std::codecvt<Elem, char, std::mbstate_t>;;
Elem: char16_t, char32_t或者wchar_t
Mode: 指出使用 Big-Endian 仍是 Little-Endian 還有讀寫的時候是否跳 BOM。(默認爲Big-Endian且不考慮BOM的).
主要目的: 用於 UTF16和UCS2/UCS4之間的相互轉換.
std::codecvt_utf8_uft16 : public std::codecvt
template< class Elem, unsigned long Maxcode = 0x10ffff, std::codecvt_mode Mode = (std::codecvt_mode)0 > class codecvt_utf8_utf16 : public std::codecvt<Elem, char, std::mbstate_t>;
Elem: char16_t, char32_t或者wchar_t
Mode: 指出使用 Big-Endian 仍是 Little-Endian 還有讀寫的時候是否跳 BOM。(默認爲Big-Endian且不考慮BOM的).
主要目的: 用於UTF8和UTF16之間相互轉換.