C++ – 使用标准库std::use_facet和std::codecvt进行跨平台gbk与utf8字符集转换
本文作者:StubbornHuang
版权声明:本文为站长原创文章,如果转载请注明原文链接!
原文标题:C++ – 使用标准库std::use_facet和std::codecvt进行跨平台gbk与utf8字符集转换
原文链接:https://www.stubbornhuang.com/2522/
发布于:2023年02月27日 16:24:40
修改于:2023年02月27日 16:43:56

1 C++标准库中与字符集转换相关的类
1.1 std::use_local和facet
C++中的std::local每个本地化环境对象至少包含了以下的标准facet,
- std::collate
、std::collate - std::ctype
、 std::ctype - std::codecvt<char, char, std::mbstate_t>
std::codecvt<char16_t, char, std::mbstate_t> - std::codecvt<char32_t, char, std::mbstate_t>
std::codecvt<wchar_t, char, std::mbstate_t> - std::moneypunct
std::moneypunct<char, true> - std::moneypunct
std::moneypunct<wchar_t, true> - std::money_get
、std::money_get - std::money_put
、std::money_put - std::numpunct
、std::numpunct - std::num_get
、std::num_get - std::num_put
、std::num_put - std::time_get
、std::time_get - std::time_put
、std::time_put - std::messages
、std::messages
除了这些标准化的facet之外,我们也可以自定义一个facet对象,上述标准化的facet对象都有自己的特定功能,如果我们要访问一个std::local对象中特定的facet对象则需要使用模板方法std::use_facet
,
template< class Facet >
const Facet& use_facet( const std::locale& loc );
那么使用std::use_facet
的作用是什么呢?使用std::use_facet
主要是把一个facet类实例化成为了一个对象,然后就可以使用这个对象的成员函数。
1.2 std::codecvt
在1.1节中我们可以看到,其实std::codecvt
就是一个标准的facet,其原型如下
template<
class InternT,
class ExternT,
class StateT
> class codecvt;
其中,InternT
表示内部编码,ExternT
表示外部编码,StateT
则是不同转换方式的标志。比如说std::codecvt<wchar_t, char, std::mbstate_t>
,其内部编码就是wchar_t
,而外部编码就是char
,而std::codecvt<wchar_t, char, std::mbstate_t>
就是一个在系统原生宽和窄字符集进行转换的一个facet。
而std::codecvt
有以下两个成员函数:
- out:调用do_out虚函数,而do_out虚函数主要是将字符串从内部编码InternT转为外部编码ExternT
- in:调用do_in虚函数,而do_in虚函数则主要是将字符串从外部编码ExternT转为内部编码InternT
所以我们如果调用std::codecvt<wchar_t, char, std::mbstate_t>
的成员函数out
,则可以将字符串从wchar_t转换为char;调用成员函数in
则可以将字符串从char转化为wchar_t。
1.3 std::wstring_convert
在字符集的转换过程中还会用到std::wstring_convert
,其函数模板如下
template< class Codecvt,
class Elem = wchar_t,
class Wide_alloc = std::allocator<Elem>,
class Byte_alloc = std::allocator<char> >
class wstring_convert;
其函数模板的作用主要是进行窄字符std::string与宽字符std::wstring之间的转换,其有常用的两个成员函数
- from_bytes:将byte string转换为wide string
- to_bytes:将wide string转换为byte string
不过遗憾的是,这个函数在C++11启用,但是在C++17就被弃用了,所以在使用下述代码时应选择正确版本的编译器。
2 使用std::use_local和std::codecvt进行跨平台gbk和utf8字符集转换
在下述代码中,先使用std::use_facet实例化std::codecvt<wchar_t, char, std::mbstate_t>
对象,然后再调用其out
和in
成员函数进行宽窄字符的转换,然后使用std::wstring_convert
完成字符集的转换,示例的代码如下,可以对照代码以及第1节的描述梳理思路
#include <iostream>
#include <string>
#include <vector>
#include <locale>
#include <codecvt>
using namespace std;
std::string gb2312_to_utf8(std::string const& strGb2312)
{
std::vector<wchar_t> buff(strGb2312.size());
#ifdef _MSC_VER
std::locale loc("zh-CN");
#else
std::locale loc("zh_CN.GB18030");
#endif
wchar_t* pwszNext = nullptr;
const char* pszNext = nullptr;
mbstate_t state = {};
int res = std::use_facet<std::codecvt<wchar_t, char, mbstate_t> >
(loc).in(state,
strGb2312.data(), strGb2312.data() + strGb2312.size(), pszNext,
buff.data(), buff.data() + buff.size(), pwszNext);
if (std::codecvt_base::ok == res)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> cutf8;
return cutf8.to_bytes(std::wstring(buff.data(), pwszNext));
}
return "";
}
std::string utf8_to_gb2312(std::string const& strUtf8)
{
std::wstring_convert<std::codecvt_utf8<wchar_t>> cutf8;
std::wstring wTemp = cutf8.from_bytes(strUtf8);
#ifdef _MSC_VER
std::locale loc("zh-CN");
#else
std::locale loc("zh_CN.GB18030");
#endif
const wchar_t* pwszNext = nullptr;
char* pszNext = nullptr;
mbstate_t state = {};
std::vector<char> buff(wTemp.size() * 2);
int res = std::use_facet<std::codecvt<wchar_t, char, mbstate_t> >
(loc).out(state,
wTemp.data(), wTemp.data() + wTemp.size(), pwszNext,
buff.data(), buff.data() + buff.size(), pszNext);
if (std::codecvt_base::ok == res)
{
return std::string(buff.data(), pszNext);
}
return "";
}
int main()
{
std::string str_utf8 = u8"你好";
std::string str_gbk = utf8_to_gb2312(str_utf8);
std::cout << str_gbk << std::endl;
std::string str_res = gb2312_to_utf8(str_gbk);
std::cout << str_res << std::endl;
return 0;
}
输出结果:
你好
浣犲ソ
参考链接
当前分类随机文章推荐
- C++ - 控制台程序在控制台窗口可变参数格式化带颜色输出日志信息 阅读3049次,点赞0次
- C++ – 字节数组byte[]或者unsigned char[]与long long的相互转换 阅读1467次,点赞0次
- C++ - 将Unicode std::wstring字符串转换为Unicode std::string转义字符,类似于\uxxxx的形式 阅读1423次,点赞0次
- C++ - 使用模板和智能指针构建一个双向链表工具类 阅读815次,点赞0次
- C++ - 我在项目实际开发中用到的第三方库/开源项目,涵盖网络、加密解密、GUI、网络、音视频、图片等等 阅读132次,点赞0次
- C++ - Windows下字符串UTF8编码转ANSI,ANSI转UTF8编码 阅读347次,点赞0次
- C++ - 我的代码风格/代码规范备忘 阅读765次,点赞0次
- 计算几何 - C++计算两个二维向量的夹角 阅读3861次,点赞3次
- C++ - C++类的特殊成员函数,析构函数,拷贝构造函数,移动构造函数,赋值运算符,移动赋值运算符介绍和基础语法 阅读758次,点赞0次
- C++ - queue存储动态指针时正确释放内存 阅读5234次,点赞2次
全站随机文章推荐
- 资源分享 - GLSL Essentials - Enrich your 3D scenes with the power of GLSL 英文高清PDF下载 阅读2103次,点赞0次
- UnrealEngine4 - Can not find such file SceneRenderTargets.h,在UE4 C++层中正确的使用FSceneRenderTargets类 阅读2678次,点赞0次
- 2023年完美货币PerfectMoney提现到国内银行卡以及提现到支付宝/微信账户的保姆级教程 阅读829次,点赞0次
- WordPress - 在文章被复制时弹出弹窗提示转载注明原创 阅读3035次,点赞2次
- 书籍翻译 – Fundamentals of Computer Graphics, Fourth Edition,第4章 Ray Tracing中文翻译 阅读1688次,点赞7次
- Mediapipe - 使用Mediapipe Holistic识别身体、手、面部全身关节点 阅读5604次,点赞3次
- C++ - 字节数组byte[]或者unsigned char[]与double的相互转换 阅读2013次,点赞0次
- C++11 - 委托机制的实现TinyDelegate 阅读1321次,点赞0次
- OpenCV - 新建一个图片,并在图片上画由一点到另一点的直线,采用反走样形式 阅读2867次,点赞0次
- 资源分享 - Digital Character Development - Theory and Practice , First Edition 英文高清PDF下载 阅读1312次,点赞0次
评论
167