在处理东方语言(中日韩)时,经常会遇到各种编码问题,而且被这类问题搞的晕头转向。到网上查资料,看的也是一头雾水,最后往往是误打误撞的把问题解决了,自己仍然稀里糊涂。
这篇文章介绍了如何在最常见的编码方式(unicode, utf-8, ansi)之间进行转换,结合代码实例,清晰明了,方便读者理解,例子也可以直接拿来使用。本文推荐给经常对文字字符串进行处理的程序员阅读,使其掌握字符转换的一些基本方法。
正文
c++的项目,字符编码是一个大坑,不同平台之间的编码往往不一样,如果不同编码格式用一套字符读取格式读取就会出现乱码。因此,一般都是转化成utf-8这种平台通用,且支持性很好的编码格式。
unicode、utf-8的概念不做过多解释,这里说一下ansi,我第一次看到这个名词,我看成了ascii。被mentor狠批一顿。
ansi是一种字符代码,为使计算机支持更多语言,通常使用 0x00 ~ 0x7f范围的1 个字节来表示 1 个英文字符。超出此范围使用0x80~0xffff来编码,即扩展的ascii编码。
不同的国家和地区制定了不同标准,由此产生了 gb2312、gbk、gb18030、big5、shift_jis 等各自的编码标准。这些使用多个字节来代表一个字符的各种汉字延伸编码方式,称为 ansi 编码。在简体中文windows操作系统,ansi 编码代表 gbk 编码;在繁体中文windows操作系统,ansi编码代表big5;在日文windows操作系统,ansi 编码代表 shift_jis 编码。
以上内容摘自百度百科,可以看出,ansi和ascii还是有关系的。ansi也叫本地码。
我们要做到能在unicode、utf-8、ansi这三种编码格式中自由转换。如下图所示:
在c++中,要怎么做呢?当然是用标准库的东西啦,c++11对国际化标准做得还是可以的,提供了这些接口,正如图中虚线所示,标准库没有提供utf-8到ansi的互相转化接口,但是我们可以自己封转接口,借用这条路(utf-8 unicode ansi)来实现。
因此,接下来就聊聊utf8 unicode和unicode ansi。
utf8 unicode
先看代码:
std::string unicodetoutf8(const std::wstring & wstr){ std::string ret; try { std::wstring_convert< std::codecvt_utf8 > wcv; ret = wcv.to_bytes(wstr); } catch (const std::exception & e) { std::cerr << e.what() << std::endl; } return ret;}std::wstring utf8tounicode(const std::string & str){ std::wstring ret; try { std::wstring_convert< std::codecvt_utf8 > wcv; ret = wcv.from_bytes(str); } catch (const std::exception & e) { std::cerr << e.what() << std::endl; } return ret;}
utf-8是多字节字符串(multibyte string),而unicode是宽字符字符串(wchar_t string)。
而c++11提供了wstring_convert这个类,这个类可以在wchar_t string和multibyte string之间来回转换;
而codecvt_utf8可以提供utf-8的编码规则。这个类在#include 中。有了wstring_convert提供宽字符字符串到多字节字符串的转化,而这个转换规则由codecvt_uft8提供。这样子就可以实现utf8和unicode的互相转换。
从utf8到unicode调用成员函数wstring_convert::from_bytes;
从unicode到utf8调用成员函数wstring_convert::to_bytes;
unicode ansi
std::string unicodetoansi(const std::wstring & wstr){ std::string ret; std::mbstate_t state = {}; const wchar_t *src = wstr.data(); size_t len = std::wcsrtombs(nullptr, &src, 0, &state); if (static_cast(-1) != len) { std::unique_ptr buff(new char[len + 1]); len = std::wcsrtombs(buff.get(), &src, len, &state); if (static_cast(-1) != len) { ret.assign(buff.get(), len); } } return ret;}std::wstring ansitounicode(const std::string & str){ std::wstring ret; std::mbstate_t state = {}; const char *src = str.data(); size_t len = std::mbsrtowcs(nullptr, &src, 0, &state); if (static_cast(-1) != len) { std::unique_ptr buff(new wchar_t[len + 1]); len = std::mbsrtowcs(buff.get(), &src, len, &state); if (static_cast(-1) != len) { ret.assign(buff.get(), len); } } return ret;}
标准库提供了wcsrtombs和mbsrtowcs这两个函数,当然c的标准库也提供了这两个函数。
讲下wcsrtombs,这个函数把宽字符串转成多字节字符串。编码规则受地域的lc_ctype影响。因此这个函数可以用于本地码的转化(和本地的编码息息相关)。
因此,有关于本地码的使用,在代码中要加上下列语句:
setlocale(lc_ctype, );
目的是让本地码生效,这条代码的作用就是让c++语言的locale(地域)和本地的地域相同。在linux下可以运行locale命令看看:
可以看到,lc_ctype = en_us.utf-8,这表示英文,英国,utf-8编码,也就是说本地码就是这个。
当然,你也可以在setlocale中指定一些编码规则,把wcsrtombs用于别的编码转化,但是,这里不推荐,因为setlocale是全局的,设置了这个就会影响其他地方的编码。
wcsrtombs的四个参数分别代表什么意思呢?
std::size_t wcsrtombs( char* dst, const wchar_t** src, std::size_t len, std::mbstate_t* ps );
dst,转化后的结果存入dst指向的内存;
src,待转化的字符串的指针的指针;
len,dst指向内存的可用字节数;
ps,转换的状态,一般默认初始化就好了;
return type,转化后结果的长度,不包含。
注意:如果dst == nullptr,这个时候wcstombs的返回值表示会有这么多字节的结果产生,因此,我们可以拿到这个返回值去新建一个数组来存储new char[len + 1]。所以,一般调用两次wcstombs。
mbsrtowcs同理。
utf-8 ansi
以unicode为中介装换便是。
std::string utf8toansi(const std::string & str){ return unicodetoansi(utf8tounicode(str));}std::string ansitoutf8(const std::string & str){ return unicodetoutf8(ansitounicode(str));}
总结
c++11的标准库还是挺强大的,虽然这么强大,但是很多特性还不了解,因此还是要多扩宽自己的视野,不然有好东西都不知道用,那就棒槌了。
对了,在linux下加上setlocale(lc_ctype, )后程序在命令行中可以正常显示,不加有可能不正常显示,原因是setlocale(lc_ctype, )也影响了cout,全局的嘛;而在codeblocks下不能正常显示,不知道为什么,但是调试的过程中,观察到了正常的结果;visual studio中没有做实验,不过应该没问题。
施普林格与OpenAI达成协议,让ChatGPT为新闻文章进行总结摘要
华盛顿大学将投入600万美元成立AR/VR研究中心
魅族X8幻蓝版高清图赏
智能热水器加入语音功能的价值
如何管理4至20mA电流环路中的压降?如何确定环路的适当电源电压?
C++字符编码转换的基本方法
麦本本金麦6A轻薄型笔记本体验 在2K价位区间内性价比优势相当明显
ZDS2024:一款面向工程师的更全面的示波器
今年最终户用光伏新增装机量将超过10GW,达到一个新的里程碑
KAIST最终赢得了“AI世界杯”冠军
硕盟usb3.0转rj45千兆以太网免驱网卡
荣耀Magic2续航测试并不支持无线充电
什么是芯片老化测试?芯片老化测试系统NSAT-2000解决方案
连接器厂商信音电子登录创业板
立体声数模转换芯片GC4344的性能有哪些?
您的物联网,还是我的物联网?
介绍脑机接口在应用系统实现取得的成果以及目前进展和未来发展趋势
兆科今日分享:使用导热绝缘材料需要注意哪几个细节呢?
荣耀20评测 一款令人眼前一亮的科技潮品
5G产业加速跑能带来什么