Locale:標準庫字符編碼轉換概覽.(從C++17開始棄用)

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之間相互轉換.

相關文章
相關標籤/搜索