当前位置:首页 > > 21ic电子网
[导读]这篇文章介绍了如何在最常见的编码方式(Unicode, UTF-8, ANSI)之间进行转换,结合代码实例,清晰明了,方便读者理解,例子也可以直接拿来使用。

【CPP开发者导读】:在处理东方语言(中日韩)时,经常会遇到各种编码问题,而且被这类问题搞的晕头转向。到网上查资料,看的也是一头雾水,最后往往是误打误撞的把问题解决了,自己仍然稀里糊涂。


这篇文章介绍了如何在最常见的编码方式(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++中,要怎么做呢?当然是用标准库的东西啦,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< char [] > 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< wchar_t [] > 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命令看看:

一文详解C++字符编码的转换

可以看到,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,转化后结果的长度,不包含\0。


注意:如果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中没有做实验,不过应该没问题。


作者:FlushHip
来源:https://blog.csdn.net/flushhip/article/details/82836867

免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

21ic电子网

扫描二维码,关注更多精彩内容

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭