C++ 存在多種方式實現(xiàn) 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 ,網(wǎng)上有很多,此處不做過多描述。
由于項目需要去掉 Qt 依賴,或者無法使用 Qt,所有給出以下兩種方法。
2 - 使用 std::codecvt
C++標準庫封裝了部分轉碼方法,需要通過 unicode 中轉,調用 <codecvt> 與 <clocale> 來實現(xiàn)。
首先實現(xiàn)四個基礎方法
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;
}
然后實現(xiàn) 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;
}
然后實現(xiàn)最外層的方法
class String {
public:
static std::string Utf8ToAnsi(const std::string& str);
static std::string AnsiToUtf8(const std::string& str);
};
只需要級聯(lián)調用即可
std::string String::Utf8ToAnsi(const std::string& str)
{
return UnicodeToAnsi(Utf8ToUnicode(str));
}
std::string String::AnsiToUtf8(const std::string& str)
{
return UnicodeToUtf8(AnsiToUnicode(str));
}
主函數(shù)入口處需設置 setlocale,此處調用為了使 ANSI 編碼生效,由于 ANSI 在不同平臺下表示的編碼不同。
// to let ANSI take effects to enable AnsiToUtf8
setlocale(LC_CTYPE, "");
完整代碼 String.h,實現(xiàn)一個純接口類
#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 現(xiàn)在較新版本的編譯器一般都支持,如果不支持需要換成
#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 庫都會影響,有可能會出現(xiàn)問題,所以建議第三種方法。
3 - 使用 WinAPI 和 iconv
Windows 平臺使用 Win API, linux 平臺使用 iconv 庫
首先實現(xiàn)一個 linux 下的通用函數(shù),由于直接使用 std::string 和 iconv 接口會出現(xiàn)轉換失敗的問題。
// 根據(jù)不同的平臺包含不同的頭文件
#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
實現(xiàn) GBK 轉 UTF-8 的接口,設置轉換失敗和非 Windows 和非 Linux 系統(tǒng),返回原字符串。
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
}
實現(xiàn) UTF-8 轉 GBK 的接口,與前者一樣,非 Windows 和非 Linux 系統(tǒng)未處理和處理失敗返回原字符串文章來源:http://www.zghlxwxcb.cn/news/detail-698688.html
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 兩個平臺均驗證測試可行。文章來源地址http://www.zghlxwxcb.cn/news/detail-698688.html
到了這里,關于使用 C++ 方式實現(xiàn) GBK 到 UTF-8 轉碼 (win / linux)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!