在C++11中,如何將一種編碼的string轉換為另一種編碼的string?
比如將一個GBK編碼的string轉換為UTF-8的string,用boost庫可以輕而易舉地解決:
#include &
#include &
inline std::string tr(const std::string str) {
return boost::locale::conv::between(str, "UTF-8", "GBK");
}
請問在C++11中,如何使用標準庫設施(如concvt等)來解決這個問題?
C++11的std::wstring_convert配合std::codecvt模板類完全可以解決這個問題,不會出現@vczh 所說修改了全局locale會導致污染其他庫的問題。
這兩個模板類的功能是:
std::wstring_convert:轉碼器,接收一個類似codecvt描述編碼轉換特性的模板參數,用於將本地化的寬字元wstring和指定編碼的位元組化string進行互轉。std::codecvt:編碼轉換特性類,用在wstring_convert的模板參數中來指定使用哪種編碼。所以編碼A和B互轉的實現方式就是:藉助本地化寬字元串,先將以A編碼的string轉為本地化的wstring,再將本地化的wstring轉為B編碼後的string。
codecvt一般使用下面兩個特化子類:
std::codecvt_utf8&std::codecvt_byname&
const char* GBK_LOCALE_NAME = ".936"; //GBK在windows下的locale name
string gbk_str {"xCCxCC"}; //0xCCCC,"燙"的GBK碼
//構造GBK與wstring間的轉碼器(wstring_convert在析構時會負責銷毀codecvt_byname,所以不用自己delete) 再將wstring轉為UTF8 string 轉碼就完成了。utf8_str里的內容應該是"xE7x83xAB"(燙的UTF8)。
wstring_convert&
wstring tmp_wstr = cv1.from_bytes(gbk_str);
wstring_convert&
string utf8_str = cv.to_bytes(tmp_wstr);
在Windows下面你就應該用API,OSX也有自己的API,Linux還有自己locale的庫。最好的方法就是自己對這個函數寫三遍,在不同的操作系統下鏈接不同的實現。
C和C++ runtime帶的函數,locale的設置是全局的,一不小心就會跟別的庫衝突。不要這麼做,避免各種爛事。題主可以參考 std::codecvt 和 std::wstring_convertwstring_convert 類
&
GCC 5.0 libc++ 還有 Visual C++ 2012 支持編碼轉換 ,頭文件是 codecvt,
bool WideStringToString(const std::wstring src,std::string str)
{
std::locale sys_locale("");
const wchar_t* data_from = src.c_str();
const wchar_t* data_from_end = src.c_str() + src.size();
const wchar_t* data_from_next = 0;
int wchar_size = 4;
char* data_to = new char[(src.size() + 1) * wchar_size];
char* data_to_end = data_to + (src.size() + 1) * wchar_size;
char* data_to_next = 0;
memset( data_to, 0, (src.size() + 1) * wchar_size );
typedef std::codecvt&
mbstate_t out_state = {0};
auto result = std::use_facet&
out_state, data_from, data_from_end, data_from_next,
data_to, data_to_end, data_to_next );
if( result == convert_facet::ok)
{
str = data_to;
delete[] data_to;
return true;
}
delete[] data_to;
return false;
}
bool StringToWideString( const std::string src,std::wstring wstr)
{
std::locale sys_locale("");
const char* data_from = src.c_str();
const char* data_from_end = src.c_str() + src.size();
const char* data_from_next = 0;
wchar_t* data_to = new wchar_t[src.size() + 1];
wchar_t* data_to_end = data_to + src.size() + 1;
wchar_t* data_to_next = 0;
wmemset( data_to, 0, src.size() + 1 );
typedef std::codecvt&
mbstate_t in_state = {0};
auto result = std::use_facet&
in_state, data_from, data_from_end, data_from_next,
data_to, data_to_end, data_to_next );
if( result == convert_facet::ok )
{
wstr = data_to;
delete[] data_to;
return true;
}
delete[] data_to;
return false;
}
bool WCharStringToUTF8String(const std::wstring wstr,std::string u8str)
{
std::wstring_convert&
u8str= conv.to_bytes(wstr);
return true;
}
bool UTF8StringToWCharString(const std::string u8str,std::wstring wstr)
{
std::wstring_convert&
wstr=conv.from_bytes( u8str );
return true;
}
// 貼段公司的代碼吧,wchar_t在不同系統尺寸不一樣?所以包裝了個vxUWChar
void utf162utf8(const vxUWChar* str, char* dst,int lens)
{
#ifdef _WIN32
WideCharToMultiByte(CP_UTF8,0,(LPCWSTR)str,(int)vxUWcslen(str),dst,lens,NULL,NULL);
#elif defined(__APPLE__)
CFStringRef strref = CFStringCreateWithBytes(kCFAllocatorDefault,(const UInt8*)str,vxUWcslen(str)*2,kCFStringEncodingUTF16,false);
if(strref)
{
CFStringGetCString(strref,(char*)dst,lens,kCFStringEncodingUTF8);
CFRelease(strref);
}
#else
iconv_t cd = iconv_open("UTF-8", "UTF-16LE");
size_t insize = vxUWcslen(str)*2;
size_t outsize = lens;
int ret = iconv(cd,(char**)str,insize,(char**)dst,outsize);
iconv_close(cd);
#endif
}
推薦閱讀:
※如何將一個函數編譯成二進位文件?
※微軟對 C++ 的影響力有多大?
※為什麼要有堆區和棧區呢?
※如何將一個有序的數組隨機排序?
※從事C#開發兩年,25歲轉Cocos2d-x開發,會不會太晚?