UTF_8与GBK
在windows平台下sizeof(wchar_t)为2,而在linux平台下sizeof(wchar_t)为4;
在windows平台下宽字符(或字符串)字面量使用UTF-16编码,linux平台下使用UTF-32编码。
MultiByteToWideChar、WideCharToMultiBytestd::string UTF8ToGBK(const std::string& strUTF8)
{
int len = MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), -1, NULL, 0);
WCHAR* wszGBK = new WCHAR[len + 1];
memset(wszGBK, 0, len * 2 + 2);
MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)(LPCTSTR)strUTF8.c_str(), -1, wszGBK, len);
len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
char *szGBK = new char[len + 1];
memset(szGBK, 0, len + 1);
WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
std::string strTemp(szGBK);
delete[]szGBK;
delete[]wszGBK;
return strTemp;
}
std::string GBKToUTF8(const std::string& strGBK)
{
std::string strOutUTF8 = "";
WCHAR * str1;
int n = MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, NULL, 0);
str1 = new WCHAR[n];
MultiByteToWideChar(CP_ACP, 0, strGBK.c_str(), -1, str1, n);
n = WideCharToMultiByte(CP_UTF8, 0, str1, -1, NULL, 0, NULL, NULL);
char * str2 = new char[n];
WideCharToMultiByte(CP_UTF8, 0, str1, -1, str2, n, NULL, NULL);
strOutUTF8 = str2;
delete[]str1;
str1 = NULL;
delete[]str2;
str2 = NULL;
return strOutUTF8;
}
MultiByteToWideChar、WideCharToMultiByte可以改变多字节与宽字节
CodePage参数控制字符集:
CodePage——指定要转换成的字符集代码页,它可以是任何已经安装的或系统自带的字符集,可选择以下代码页:
CP_ACP //当前系统ANSI代码页
CP_MACCP //当前系统Macintosh代码页
CP_OEMCP //当前系统OEM代码页,一种原始设备制造商硬件扫描码
CP_SYMBOL //Symbol代码页,用于Windows 2000及以后版本
CP_THREAD_ACP //当前线程ANSI代码页,用于Windows 2000及以后版本
CP_UTF7 //UTF-7,设置此值时lpDefaultChar和lpUsedDefaultChar都必须为NULL
CP_UTF8 //UTF-8,设置此值时lpDefaultChar和lpUsedDefaultChar都必须为NULL
用 GetLocaleInfo 函数获取当前系统的代码页,936: 简体中文, 950: 繁体中文,949:韩文
ATL封装_bstr_#include
#pragma comment(lib, "comsuppw.lib")
string ws2s(const wstring& ws)
{
_bstr_t t = ws.c_str();
char* pchar = (char*)t;
string result = pchar;
return result;
}
wstring s2ws(const string& s)
{
_bstr_t t = s.c_str();
wchar_t* pwchar = (wchar_t*)t;
wstring result = pwchar;
return result;
}
iconvint code_convert(char *from_charset, char *to_charset, char *inbuf, size_t inlen,
char *outbuf, size_t outlen) {
iconv_t cd;
char **pin = &inbuf;
char **pout = &outbuf;
cd = iconv_open(to_charset, from_charset);
if (cd == 0)
return -1;
memset(outbuf, 0, outlen);
if (iconv(cd, pin, &inlen, pout, &outlen) == -1)
return -1;
iconv_close(cd);
*pout = '\0';
return 0;
}
int u2g(char *inbuf, size_t inlen, char *outbuf, size_t outlen) {
return code_convert("utf-8", "gb2312", inbuf, inlen, outbuf, outlen);
}
int g2u(char *inbuf, size_t inlen, char *outbuf, size_t outlen) {
return code_convert("gb2312", "utf-8", inbuf, inlen, outbuf, outlen);
}
使用C++11标准库进行编码转换
下面是一段测试代码,print_code_uint_sequence函数模板用于输出字符串的码元序列。
#include
#include
#include
#include
template
void print_code_unit_sequence(tStringType str)
{
using char_type = typename tTraits::char_type;
static_assert(std::is_same::value || std::is_same::value || std::is_same::value, "error");
using unsigned_char_type = typename std::make_unsigned::type;
using unsigned_int_type = typename std::make_unsigned::type;
int w = std::is_same::value ? 2 : std::is_same::value ? 4 : 8;
for(auto c : str) {
auto value = static_cast(static_cast(c));
std::cout << "0x" << std::hex << std::uppercase << std::setw(w) << std::setfill('0') << value << ' ';
}
}
int main()
{
std::string u8_str = u8""; // utf-8
std::u16string u16_str = u""; // utf-16
std::u32string u32_str = U""; // ucs4
std::cout << "utf-8: ";
print_code_unit_sequence(u8_str);
std::cout << std::endl;
std::cout << "utf-16: ";
print_code_unit_sequence(u16_str);
std::cout << std::endl;
std::cout << "ucs4: ";
print_code_unit_sequence(u32_str);
std::cout << std::endl;
}
C++11标准库在头文件中定义了3个Unicode编码转换的Facet
std::codecvt_utf8 封装了UTF-8与UCS2及UTF-8与UCS4的编码转换
std::codecvt_utf16 封装了UTF-16与UCS2及UTF-16与UCS4的编码转换
std::codecvt_utf8_utf16 封装了UTF-8与UTF-16的编码转换
当要转换的字符串为std::basic_string使用
template
class Elem = wchar_t,
class Wide_alloc = std::allocator,
class Byte_alloc = std::allocator>
class wstring_convert;
UTF-8与UTF-16编码转换
UTF-8与UTF-16的编码转换使用std::codecvt_utf8_utf16类模板,其中Elem用于存储UTF-16码元,可以是char16_t、char32_t或wchar_t(这些类型都至少能够存储16bit)。
std::wstring_convert<:codecvt_utf8_utf16>, char16_t> cvt;
std::u16string u16_cvt_str = cvt.from_bytes(u8_source_str); // utf-8 to utf-16
std::string u8_cvt_str = cvt.to_bytes(u16_cvt_str); // utf-16 to utf-8
UTF-8与UCS2编码转换及UTF-8与UCS4编码转换
UTF-8与UCS2或UCS4编码转换使用std::codecvt_utf8类模板,当Elem为char16_t时转换为UTF-8与UCS2,当Elem为char32_t时转换为UTF-16与UCS4,当Elem为wchar_t时转换取决于实现。
std::wstring_convert<:codecvt_utf8>, char16_t> utf8_ucs2_cvt;
std::u16string ucs2_cvt_str = utf8_ucs2_cvt.from_bytes(u8_source_str); // utf-8 to ucs2
std::string u8_str_from_ucs2 = utf8_ucs2_cvt.to_bytes(ucs2_cvt_str); // ucs2 to utf-8
std::wstring_convert<:codecvt_utf8>, char32_t> utf8_ucs4_cvt;
std::u32string ucs4_cvt_str = utf8_ucs4_cvt.from_bytes(u8_source_str); // utf-8 to ucs4
std::string u8_str_from_ucs4 = utf8_ucs4_cvt.to_bytes(ucs4_cvt_str); // ucs4 to utf-8
UTF-16与UCS2编码转换及UTF-16与UCS4编码转换
UTF-16转UCS2或UCS4使用std::codecvt_utf16类模板
这里以UTF-16与UCS4的转换为例Elem为char32_t,UTF-16与UCS2的转换类似只是Elem需为char16_t。
由于std::wstring_convert是用于在byte string和wide string之间转换,使用std::codecvt_utf16时UTF-16字符串作为byte string,因此使用这个转换时就需要考虑字节序的问题。std::codecvt_utf16类模板的第3个模板参数Mode类型为std::codecvt_mode
enum codecvt_mode {
consume_header = 4,
generate_header = 2,
little_endian = 1
};consume_header 告诉codecvt需要处理输入的byte string中的BOM(Byte Order Mark)
generate_header 告诉codecvt在输出的byte string中添加BOM
little_endian 告诉codecvt将byte string的字节序视为小端(Little Endian),默认为大端(Big Endian)
std::wstring_convert<:codecvt_utf16 char32_t> utf16le_cvt; // little endian
std::wstring_convert<:codecvt_utf16 char32_t> utf16be_cvt; // default big endian
std::u32string u32_str_from_le = utf16le_cvt.from_bytes(u16le_byte_str); // utf-16 to ucs4
std::u32string u32_str_from_be = utf16be_cvt.from_bytes(u16be_byte_str); // utf-16 to ucs4
BOM(Byte Order Mark)
字节序标记是插入到以UTF-8、UTF-16或UTF-32编码Unicode文件开头的特殊标记,用于标识文本编码及字节序。
UTF-8 0xEF 0xBB 0xBF
UTF-16 BE 0xFE 0xFF
UTF-16 LE 0xFF 0xFE
UTF-32 BE 0x00 0x00 0xFE 0xFF
UTF-