• 计算机图形学与计算几何经典必备书单整理,下载链接可参考:https://www.stubbornhuang.com/1256/

  • 欢迎大家交换友链,可在https://www.stubbornhuang.com/申请友情链接进行友链交换申请!

  • 感谢大家访问本站,希望本站的内容可以帮助到大家!

  • 本站会放置Google广告用于维持域名以及网站服务器费用。

  • 问题反馈可发送邮件到stubbornhuang@qq.com

  • 在本站开通年度VIP,无限制下载本站资源和阅读本站文章

  • 工资「喂饱肚子」,副业「养活灵魂」!

  • 本站由于前段时间遭受到大量临时和国外邮箱注册,所以对可注册的邮箱类型进行了限制!

  • 如果觉得本站的内容有帮助,可以考虑打赏博主哦!

C++ – 使用标准库std::use_facet和std::codecvt进行跨平台gbk与utf8字符集转换

C++ 发布于2023-02-27 阅读 3,277次 0次评论 0次点赞 本文共3731个字,阅读需要10分钟。

1 C++标准库中与字符集转换相关的类

1.1 std::use_local和facet

C++中的std::local每个本地化环境对象至少包含了以下的标准facet,

除了这些标准化的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>对象,然后再调用其outin成员函数进行宽窄字符的转换,然后使用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;
}

输出结果:

你好
浣犲ソ

参考链接

欢迎扫码关注我的微信公众号,及时获取文章更新

微信公众号二维码

本文作者:StubbornHuang

版权声明:本文为站长原创文章,如果转载请注明原文链接!

原文标题:C++ – 使用标准库std::use_facet和std::codecvt进行跨平台gbk与utf8字符集转换

原文链接:https://www.stubbornhuang.com/2522/

发布于:2023年02月27日 16:24:40

修改于:2023年06月27日 9:41:01

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

文章末尾
上一篇
WordPress - 在后台管理面板添加禁止某一个用户登录的功能
WordPress
下一篇
C++ - Windows/Linux跨平台gbk与utf8字符集编码转换
C++
当前分类随机文章推荐

发表评论

您必须 [ 登录 ] 才能发表留言!

关注我们的公众号

微信公众号