使用 C++ 方式实现 GBK 到 UTF-8 转码 (win / linux)

这篇具有很好参考价值的文章主要介绍了使用 C++ 方式实现 GBK 到 UTF-8 转码 (win / linux)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++ 存在多种方式实现 GBK 到 UTF-8 的转码

1 - 使用 Qt API


一般使用C++都会想到使用 Qt API QString 将 gbk 转为 utf-8

std::string sgbk;
std::string sutf8 = QString::fromLocal8Bit(sgbk.data()).toUtf8().data());

此种方式,可以转换 Windows 平台运行时的 gbk 编码的中文字符串为 utf-8 格式,linux 下需要使用 QTextCodec ,网上有很多,此处不做过多描述。
由于项目需要去掉 Qt 依赖,或者无法使用 Qt,所有给出以下两种方法。

2 - 使用 std::codecvt


C++标准库封装了部分转码方法,需要通过 unicode 中转,调用 <codecvt> 与 <clocale> 来实现。

首先实现四个基础方法

class String {
private:
	static std::string UnicodeToUtf8(const std::wstring& wstr);
	static std::wstring Utf8ToUnicode(const std::string& str);
	static std::string UnicodeToAnsi(const std::wstring& wstr);
	static std::wstring AnsiToUnicode(const std::string& str);
};

unicode 与 utf-8 之间的相互转换

std::string String::UnicodeToUtf8(const std::wstring& wstr)
{
	std::string out;
	try {
		std::wstring_convert<std::codecvt_utf8<wchar_t>> wcv;
		out = wcv.to_bytes(wstr);
	}
	catch (const std::exception & e)
	{
		std::cerr << e.what() << std::endl;
	}
	return out;
}

std::wstring String::Utf8ToUnicode(const std::string& str)
{
	std::wstring ret;
	try
	{
		std::wstring_convert<std::codecvt_utf8<wchar_t>> wcv;
		ret = wcv.from_bytes(str);
	}
	catch (const std::exception & e)
	{
		std::cerr << e.what() << std::endl;
	}
	return ret;
}

然后实现 unicode 与 ansi 之间的转换

std::string 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 (len != static_cast<size_t>(-1))
	{
		std::unique_ptr<char[]> buff(new char[len + 1]);
		len = std::wcsrtombs(buff.get(), &src, len, &state);
		if (len != static_cast<size_t>(-1))
		{
			ret.assign(buff.get(), len);
		}
	}
	return ret;
}

std::wstring String::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 (len != static_cast<size_t>(-1))
	{
		std::unique_ptr<wchar_t[]> buff(new wchar_t[len + 1]);
		len = std::mbsrtowcs(buff.get(), &src, len, &state);
		if (len != static_cast<size_t>(-1))
		{
			ret.assign(buff.get(), len);
		}
	}
	return ret;
}

然后实现最外层的方法

class String {
public:
	static std::string Utf8ToAnsi(const std::string& str);
	static std::string AnsiToUtf8(const std::string& str);
};

只需要级联调用即可

std::string String::Utf8ToAnsi(const std::string& str)
{
	return UnicodeToAnsi(Utf8ToUnicode(str));
}

std::string String::AnsiToUtf8(const std::string& str)
{
	return UnicodeToUtf8(AnsiToUnicode(str));
}

主函数入口处需设置 setlocale,此处调用为了使 ANSI 编码生效,由于 ANSI 在不同平台下表示的编码不同。

// to let ANSI take effects to enable AnsiToUtf8
setlocale(LC_CTYPE, "");

完整代码 String.h,实现一个纯接口类

#pragma once
#include <string>
class String
{
public:
	// 对外接口
	static std::string Utf8ToAnsi(const std::string& str);
	static std::string AnsiToUtf8(const std::string& str);

private:
	// 内部调用
	static std::string UnicodeToUtf8(const std::wstring& wstr);
	static std::wstring Utf8ToUnicode(const std::string& str);
	static std::string UnicodeToAnsi(const std::wstring& wstr);
	static std::wstring AnsiToUnicode(const std::string& str);
	
	// disabled functions
	String() = delete;
	~String() = delete;
	String(const String& rhs) = delete;
	String& operator=(const String& rhs) = delete;
};

#pragma once 现在较新版本的编译器一般都支持,如果不支持需要换成
#ifndef __STRING_H__
#define __STRING_H__
#endif // __STRING_H__
防止头文件重复包含

String.cpp

#include "String.h"
#include <codecvt>
#include <iostream>

std::string String::Utf8ToAnsi(const std::string& str)
{
	return UnicodeToAnsi(Utf8ToUnicode(str));
}

std::string String::AnsiToUtf8(const std::string& str)
{
	return UnicodeToUtf8(AnsiToUnicode(str));
}

std::string String::UnicodeToUtf8(const std::wstring& wstr)
{
	std::string out;
	try {
		std::wstring_convert<std::codecvt_utf8<wchar_t>> wcv;
		out = wcv.to_bytes(wstr);
	}
	catch (const std::exception & e)
	{
		std::cerr << e.what() << std::endl;
	}
	return out;
}

std::wstring String::Utf8ToUnicode(const std::string& str)
{
	std::wstring ret;
	try
	{
		std::wstring_convert<std::codecvt_utf8<wchar_t>> wcv;
		ret = wcv.from_bytes(str);
	}
	catch (const std::exception & e)
	{
		std::cerr << e.what() << std::endl;
	}
	return ret;
}

std::string 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 (len != static_cast<size_t>(-1))
	{
		std::unique_ptr<char[]> buff(new char[len + 1]);
		len = std::wcsrtombs(buff.get(), &src, len, &state);
		if (len != static_cast<size_t>(-1))
		{
			ret.assign(buff.get(), len);
		}
	}
	return ret;
}

std::wstring String::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 (len != static_cast<size_t>(-1))
	{
		std::unique_ptr<wchar_t[]> buff(new wchar_t[len + 1]);
		len = std::mbsrtowcs(buff.get(), &src, len, &state);
		if (len != static_cast<size_t>(-1))
		{
			ret.assign(buff.get(), len);
		}
	}
	return ret;
}

由于 setlocale 会影响全局,也就是所有的 lib 库都会影响,有可能会出现问题,所以建议第三种方法。

3 - 使用 WinAPI 和 iconv


Windows 平台使用 Win API, linux 平台使用 iconv 库

首先实现一个 linux 下的通用函数,由于直接使用 std::string 和 iconv 接口会出现转换失败的问题。

// 根据不同的平台包含不同的头文件
#if defined(_WIN32) || defined(_MSC_VER) || defined(WIN64) 
#include <Windows.h>
#elif defined(__linux__) || defined(__GNUC__)
#include <iconv.h>
#endif

#if defined(__linux__) || defined(__GNUC__)
int EncodingConvert(const char* charsetSrc, const char* charsetDest, char* inbuf,
	size_t inSz, char* outbuf, size_t outSz)
{
	iconv_t cd;
	char** pin = &inbuf;
	char** pout = &outbuf;
	cd = iconv_open(charsetDest, charsetSrc);
	if (0 == cd)
	{
		std::cerr << charsetSrc << " to " << charsetDest 
		<< " conversion not available" << std::endl; 
		return -1;
	}

	if (-1 == static_cast<int>(iconv(cd, pin, &inSz, pout, &outSz)))
	{
		std::cerr << "conversion failure" << std::endl;
		return -1;
	}

	iconv_close(cd);
	**pout = '\0';
	return 0;
}
#endif

实现 GBK 转 UTF-8 的接口,设置转换失败和非 Windows 和非 Linux 系统,返回原字符串。

std::string GbkToUtf8(const std::string& str)
{
#if defined(_WIN32) || defined(_MSC_VER) || defined(WIN64)
	int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len + 1ull];
	memset(wstr, 0, len + 1ull);
	MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, wstr, len);
	len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* cstr = new char[len + 1ull];
	memset(cstr, 0, len + 1ull);
	WideCharToMultiByte(CP_UTF8, 0, wstr, -1, cstr, len, NULL, NULL);
	std::string res(cstr);

	if (wstr) delete[] wstr;
	if (cstr) delete[] cstr;

	return res;
#elif defined(__linux__) || defined(__GNUC__)
	size_t len = str.size() * 2 + 1;
	char* temp = new char[len];
	if (EncodingConvert("gb2312", "utf-8", const_cast<char*>(str.c_str()), str.size(), temp, len)
		> = 0)
	{
		std::string res;
		res.append(temp);
		delete[] temp;
		return res;
	}
	else
	{
		delete[]temp;
		return str;
	}
#else
	std::cerr << "Unhandled operating system." << std::endl;
	return str;
#endif
}

实现 UTF-8 转 GBK 的接口,与前者一样,非 Windows 和非 Linux 系统未处理和处理失败返回原字符串

std::string Utf8ToGbk(const std::string& str)
{
#if defined(_WIN32) || defined(_MSC_VER) || defined(WIN64) 
    // calculate length
	int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
	wchar_t* wsGbk = new wchar_t[len + 1ull];
	// set to '\0'
	memset(wsGbk, 0, len + 1ull);
	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, wsGbk, len);
	len = WideCharToMultiByte(CP_ACP, 0, wsGbk, -1, NULL, 0, NULL, NULL);
	char* csGbk = new char[len + 1ull];
	memset(csGbk, 0, len + 1ull);
	WideCharToMultiByte(CP_ACP, 0, wsGbk, -1, csGbk, len, NULL, NULL);
	std::string res(csGbk);

	if (wsGbk)
	{
	 	delete[] wsGbk;
	}
	
	if (csGbk)
	{
		delete[] csGbk;
	}

	return res;
#elif defined(__linux__) || defined(__GNUC__)
	size_t len = str.size() * 2 + 1;
	char* temp = new char[len];
	if (EncodingConvert("utf-8", "gb2312", const_cast<char*>(str.c_str()),
		str.size(), temp, len) >= 0)
	{
		std::string res;
		res.append(temp);
		delete[] temp;
		return res;
	}
	else
	{
		delete[] temp;
		return str;
	}

#else
	std::cerr << "Unhandled operating system." << std::endl;
	return str;
#endif
}

GBK 转 UTF-8 两个平台均验证测试可行。文章来源地址https://www.toymoban.com/news/detail-698688.html

到了这里,关于使用 C++ 方式实现 GBK 到 UTF-8 转码 (win / linux)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 织梦GBK/GB2312转utf-8编码操作步骤(全站修改方法)

    目前MIP对编码是有严格要求,必须是UTF-8,那么对于大部分GBK或者GB2312的用户只能先将网站整体进行编码转换,才能进行MIP改造,不然改造后的页面是乱码一大片。 为什么MIP只支持utf-8?目前部分手机自带浏览器仅支持UTF-8,打开GBK的网站会出现乱码,所以为了手机的兼容性,

    2023年04月24日
    浏览(60)
  • python,Pandas读取csv文件gbk编码和utf-8编码都报错

    用Pandas读取csv文件,read_csv(),使用默认的 encoding = ‘utf-8’ 和 encoding = ‘gbk’ 都报错,如下图。最终通过 统一编码方式 解决了,操作很简单,但是问题解决的探索过程并不是特别顺利,所以记录一下,给朋友们参考~ 统一编码方式,将csv文件的编码格式改为utf-8。 具体操作

    2024年01月16日
    浏览(71)
  • UTF-8、UTF-16、Unicode、GB2312、GBK、GB18030一次说清楚

    1、关于存储编码和显示编码的区别。 Unicode是显示编码,UTF-8、UTF-16、GB2312、GBK、GB18030都是存储/传输方面使用,也叫做存储编码、处理编码,你在计算机上看见的所有文字都从存储编码转成显示编码后,显示出来,当你单机保存时又从显示编码转换为存储编码存储起来。 2、

    2024年02月12日
    浏览(50)
  • UTF-8、GB2312、GBK、GB18030、ISO-8859-1(也称Latin-1):兼容ASCII编码

    ASCII码是单字节的,首位为0,后面表示的值就是Unicode码点,范围为0x00-0x7F,共表示128个字符。 UTF-8和ASCII兼容 :因为对于单字节的符号,UTF-8 编码和 ASCII 码是相同的, 所以 UTF-8 能兼容 ASCII 编码。 GB2312和ASCII兼容 :对于ASCII范围以内的字符,GB2312编码的机内码(不是区位码)

    2024年02月16日
    浏览(41)
  • 【错误记录】IntelliJ IDEA 中编译运行报错 ( 当前设置 GBK 编码 | 错误: 编码UTF-8的不可映射字�? )

    当前的 IntelliJ IDEA 设置的编码为 GBK 编码 , 选择 \\\" 菜单栏 / File / Settings \\\" 选项 , 在 \\\" File Encodings \\\" 中 , 查看 工程的编码 , 运行时报错 : 在中文注释的位置 , 编码报错 ; D:\\002_Project\\003_Java_WorkExsamplesrcmainjavaArrowCanvas.java:17 : 错误: 编码UTF-8的不可映射字�? // ����ֱ�� ^

    2024年02月14日
    浏览(51)
  • 使用sublime发现没有gbk编码

    默认情况下,我们的 Sublime是没有 GBK编码格式设置了,为了我们的文件设置为 GBK,应当安装 GBK选项插件。 安装ConvertToUTF8插件 ①首选项--package control--Install Package ②弹出新的输入框输入:ConvertToUTF8,会出现ConvertToUTF8选项,选中安装即可。 ③安装成功后,重启sublime ④比较一

    2024年02月16日
    浏览(49)
  • JavaScript实现字符编码转换utf-8/gbk(附完整源码)

    以上代码中,我们使用了JavaScript内置的TextEncoder和TextDecoder类来实现字符编码转换。这两个类是ES6新增的特性,需要在支持ES6的浏览器上才能正常运行。 使用示例: 运行结果说明转换成功。需要注意的是,在不同的浏览器中,对字符编码的支持程度可能不同,因此在使用时需

    2024年02月04日
    浏览(37)
  • linux修改locale字符集编码为UTF-8/GBK,修改语言区域为zh-CN(中文-中国)

    linux系统的语言、区域、字符集编码由`locale’ [loʊˈkæl] 决定。 对应配置文件路径: centos7 /etc/locale.conf centos6 /etc/sysconfig/i18n 以下以centos&为例 LANG= LC_CTYPE=“POSIX” LC_NUMERIC=“POSIX” LC_TIME=“POSIX” LC_COLLATE=“POSIX” LC_MONETARY=“POSIX” LC_MESSAGES=“POSIX” LC_PAPER=“POSIX” LC_NAME=“

    2024年02月13日
    浏览(77)
  • dedecms编码转换方法 gbk转UTF-8,UTF-8转GBK(推荐)

    经常遇到编码转换的问题,有的是购买了模板但是模板编码与程序编码不符,导致出现乱码.今天小编给大家分享一篇教程帮助大家解决如何转换模板文件的编码和程序的编码问题,一起看看吧! 1.如何转换模板文件编码? 首先下载一个编码转换软件 51EC模板转码专用工具v1.0免费

    2024年02月03日
    浏览(36)
  • idea打的包字符集为GBK

    1.最近对接一个打印机厂家的机器,他们对与打印数据要求字符集是UTF-8的,做完程序在自己idea上运行是是能够打印的,但是打包后,就不能够打印了。然后问了设备方是否是他们机器的原因,后面他们问了我这报错码,他们对照文档,说是打印的参数有问题,然后问我是不

    2024年02月11日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包