1. 背景介绍
C++在处理字符串时,常常会碰到宽字符(中日韩等非ACSII码字符),默认的标准库 std::string
处理的仅是 char
类型的字符串。通常,在 Unix/Linux 系统中,字符串是 UTF-8 编码的,此时,std::string
中存储的即为 UTF-8 编码后的结果。例如:“你好啊,Stick”,这句话中有 9 个字符,但实际存储在 std::string
中的内容为:"\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x95\x8a\xef\xbc\x8cStick" 实际长度为 17. 那么如何才能将 UTF-8 的编码转换为实际的 Unicode 编码呢?
2. C++ 中 UTF-8 转换为 Unicode 的方法及优缺点介绍
-
std::mbstowcs
该函数定义在<cstdlib>
头文件中,是一个 C 函数,通常配合<clocale>
头文件中的std::setlocale
使用,设置当前系统编码,将当前编码的字符串,转换为宽字符串。1
2
3
4std::setlocale(LC_ALL, "en_US.utf8");
char * str = "\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x95\x8a\xef\xbc\x8cStick";
wchar_t wstr[10];
std::mbstowcs(wstr, str, 9);该方法,在gcc 4以及更高版本中均可使用。缺点是,跨平台可能会出现问题。例如,同样的代码在 Linux 下运行良好。到了 Windows 下的 MinGW64 下就会出现问题。此外,该方法只能转换一般的宽字符,对于一些超宽字符如“𠀳”(U+20033) 则无法表示,需要使用
char32_t
类型才能表示。 -
std::wstring_convert
该函数定义在<locale>
头文件中,通常配合<codecvt>
头文件的std::codecvt_utf8
函数使用。1
2
3
4std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> convertor;
std::string str = "\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x95\x8a\xef\xbc\x8cStick"
std::wstring wstr = convertor.from_bytes(str);
std::string nstr = convertor.to_bytes(wstr);该方法,实用性很强,能够跨平台使用(MinGW64 测试正常),而且针对超宽字符也能够顺利转换,只需要将上述代码中的
wchar_t
修改为char32_t
,std::wstring
修改为std::u32string
即可。缺点是对 gcc 版本有要求,必须为 gcc 5.0 及以上版本才可以,且-std
参数必须设置为 c++11 及以上版本才可。 -
根据 UTF-8 或其他编码规则,手动书写转换代码。优点是无需考虑编译器版本,无需考虑平台限制。缺点是需要熟悉各种转换规则,增大开发难度。但是也能一劳永逸。
3. 总结
本文未对提及的方法进行速度上的测试,仅对功能性和实用性进行了测试。从这一角度出发,推荐使用 std::wstring_convert
。如果是需要维护一些老的工程代码,必须使用 gcc 4 版本的编译器,则仍旧使用原来的方案或者采用手动书写转换代码的方案,若配合上编译选项,则很容易的将代码进行高低版本的兼容。