一、配置

配置iconv在windows平台会比较麻烦,下面这个是使用vs2022编译的,可以直接使用,其他vs版本自求多福。

https://github.com/pffang/libiconv-for-Windows

引入头文件<iconv.h>和lib文件即可。

官网:libiconv - GNU Project - Free Software Foundation (FSF)

二、使用

使用倒比较简单,只有三个函数:

iconv_open 设置要转换的编码和转为的编码
iconv 转换操作
iconv_close 资源释放

1.iconv_open

iconv_t cd = iconv_open(to, from);
if ((iconv_t)(-1) == cd)
{assert(0 && "iconv_open失败!");// 会递归调用自己,不能使用debugreturn {};
}

函数返回一个句柄iconv_t,如果返回-1代表失败。出现错误可能是因为to、from设置的编码不支持,但是这里不能使用debug输出日志,因为我在debug函数将utf8编码转为本地编码使用了此函数,就发生了递归调用从而栈溢出。读者可以自行考虑怎么处理错误。

2.iconv_close

//资源释放
finally f([&]() {iconv_close(cd);
});//.h
/*** @brief RAII清理操作
*/
template<typename F>
class finally
{
public:finally(F&& func) : _func(func) {}~finally() { _func(); }
private:F _func;
};

上面这种写法无论函数在哪里return,只要脱离f的作用域,iconv句柄就会被调用iconv_close从而释放。

3.iconv

char* in_buf = (char*)buf;  //输入指针
size_t in_size = buf_size; //输入大小,直到0停止转换
char* out_buf = temp;      //输出缓冲区指针
size_t out_size = SIZE_BUFFER_STRING_CONVERT;//输出缓冲区大小if (-1 == iconv(cd, &in_buf, &in_size, &out_buf, &out_size))
{
}

这里需要句柄cd加上4个变量给予iconv函数,后面4个参数均是取地址,iconv函数会改变它们的值。

in_size我们设为要转换字符串(输入缓冲区in_buf)的大小(字节单位),当完全转换时,in_size就会变为0。那么初始大小buf_size减去in_size就是当前已经转换了的字符数量。

同理输出缓冲区大小SIZE_BUFFER_STRING_CONVERT减去out_size,就是单次调用iconv转换产生的输出大小(字节单位)。

char temp[SIZE_BUFFER_STRING_CONVERT];//缓冲区
string ret;//输出

之所以设置一个固定的输出缓冲区大小,是因为当要转换的字符串过大时,就很难一次转换完成,只能先转换一部分复制到最终的输出(string ret),然后再转换再添加到输出字符串。

所以实际代码是一个循环,返回-1并不是真的失败,当errno为E2BIG时是输出缓冲区不够用了:

do
{//直到转换完if (-1 == iconv(cd, &in_buf, &in_size, &out_buf, &out_size)){if (errno != E2BIG){assert(0 && "转换编码失败!");return {};}else{size_t num = SIZE_BUFFER_STRING_CONVERT - out_size;ret += string(temp, num);//没有转换完,重设输出位置out_size = SIZE_BUFFER_STRING_CONVERT;out_buf = temp;}}else{//完整转换,增加numassert(in_size == 0);size_t num = SIZE_BUFFER_STRING_CONVERT - out_size;if (ret.empty())//第一次就结束了,优化直接returnreturn string(temp, num);ret += string(temp, num);}
} while (in_size);

三、完整代码

整个关键的封装函数即是CvtString,代码如下:

string String::CvtString(const char* from, const char* to, const char* buf, size_t buf_size)
{//前置条件检查if (buf_size == 0)return {};iconv_t cd = iconv_open(to, from);if ((iconv_t)(-1) == cd){assert(0 && "iconv_open失败!");//TODO 会递归调用自己,不能使用debug,改为不使用编码转换的debugreturn {};}//资源释放finally f([&]() {iconv_close(cd);});char temp[SIZE_BUFFER_STRING_CONVERT];//缓冲区string ret;//输出char* in_buf = (char*)buf; //输入指针size_t in_size = buf_size;   //输入大小,直到0停止转换char* out_buf = temp;     //输出缓冲区指针size_t out_size = SIZE_BUFFER_STRING_CONVERT;//输出缓冲区大小do{//直到转换完if (-1 == iconv(cd, &in_buf, &in_size, &out_buf, &out_size)){if (errno != E2BIG){assert(0 && "转换编码失败!");return {};}else{size_t num = SIZE_BUFFER_STRING_CONVERT - out_size;ret += string(temp, num);//没有转换完,重设输出位置out_size = SIZE_BUFFER_STRING_CONVERT;out_buf = temp;}}else{//完整转换,增加numassert(in_size == 0);size_t num = SIZE_BUFFER_STRING_CONVERT - out_size;if (ret.empty())//第一次就结束了,优化直接returnreturn string(temp, num);ret += string(temp, num);}} while (in_size);return ret;
}

四、使用实例

要实现任意多字节本地编码转为utf8编码,以下调用即可:

string String::cvt_mb_u8(const char* str, const string& code_name)
{return CvtString(code_name.c_str(), "UTF-8", str, strlen(str));
}

code_name为空表示本地系统编码,也可以填入具体的编码,例如"GBK"。可以参考官网给出的全部支持的编码名字:

ICONV_OPEN

如果涉及到wstring宽字符转换,则需要转换一下,因为wchar_t在不同平台大小不一样,所以使用sizeof:

std::wstring String::cvt_mb_wc(const char* str, const string& code_name)
{string out = CvtString(code_name.c_str(), "wchar_t", str, strlen(str));assert(out.size() % sizeof(wchar_t) == 0);//必须是sizeof(wchar_t)的倍数std::wstring ret((wchar_t*)out.c_str(), out.size() / sizeof(wchar_t));return ret;
}

同理基于4字节的char32_t如此:

std::u32string String::cvt_u8_utf(const string& str)
{string out = CvtString("UTF-8", "UCS-4-INTERNAL", str.c_str(), str.size());assert(out.size() % sizeof(char32_t) == 0);//必须是sizeof(char32_t)的倍数std::u32string ret((char32_t*)out.c_str(), out.size() / sizeof(char32_t));return ret;
}//反过来则这样转换
string String::cvt_utf_u8(const utf_string& str)
{return CvtString("UCS-4-INTERNAL", "UTF-8", (char*)str.c_str(), str.size() * sizeof(wchar_t));
}

完整代码可以参考我的项目的DND.String.ixx文件:

DND3D: 基于C++20与标准库的工具集

对你有帮助请点个赞、收藏或关注。

【字符编码转换】使用iconv相关推荐

  1. iconv 判断字符编码_iconv字符编码转换全攻略

    iconv(http://www.gnu.org/software/libiconv/)是一个开源的字符编码转换库,可以"方便"的完成几乎所有的编码转换工作.说简单是因为,它常用的 ...

  2. c语言使用iconv函数实现字符编码转换

    c语言使用iconv函数实现字符编码转换 linux下提供了iconv库来实现字符编码转换,先介绍下命令行: iconv [-f encoding] [-t encoding] [inputfile ...

  3. android 使用icon进行字符编码转换

    在使用ndk开发应用程序时,有时需要字符编码转换,这里使用开源库icon进行字符编码转换,代码如下 char * convertString(const char * fromCode, const ...

  4. 《MySQL tips:隐式类型转换与隐式字符编码转换对查询效率的影响》

    维护一个交易系统,交易记录表tradelog包含交易流水号(tradeid).交易员id(operator).交易时间(t_modified)等字段. create table 'tradelog' ...

  5. 字符编码转换类(支持多国语言)

    头文件StrConvertor.h /* * 字符编码转换库,支持多国语言. */ #pragma once #include <string>class CStrConvertor { ...

  6. Android字符编码转换,GBK转UTF-8

    Android字符编码转换,GBK转UTF-8 网上看了很多都不能用,最后看到这个方法,很靠谱,分享给大家! String str; str = new String(str.getBytes(&qu ...

  7. Qt中的字符编码转换:UTF8、Unicode、GBK、ASCII、16进制字符、16进制数值

    文章目录 前言 简述 ASCII GBK Unicode UTF-8 应用场景 开发环境 编码转换 16进制数值转换为16进制字符 16进制数值转化为字符串 16进制字符串转换为Unicode字符串 ...

  8. iconv()和mb_conver_encoding()字符编码转换函数

    2019独角兽企业重金招聘Python工程师标准>>> 一. `string iconv ( string $in_charset , string $out_charset , s ...

  9. php iconv lanti1,字符编码转换iconv

    iconv命令可以将一种已知的字符集文件转换成另一种已知的字符集文件.它的作用是在多种国际编码格式之间进行文本内码的转换.iconv基于GPL公开源代码,是GNU项目的一部分. 官网地址 附件是Win ...

  10. linux下字符编码转换

    2019独角兽企业重金招聘Python工程师标准>>> 关于字符编码: 字符编码笔记:ASCII,Unicode和UTF-8: http://www.ruanyifeng.com/b ...

最新文章

  1. debian 7上安装svn
  2. Android FFmpeg系列——5 音视频同步播放
  3. 趣链 BitXHub跨链平台 (7)应用链插件
  4. JSP简单练习-包装类综合应用实例
  5. 解决element-ui table show-summary合计行不显示问题
  6. android studio break,Android Studio IDE: Break on Exception
  7. linux启动清除指定内存,柴少鹏的官方网站
  8. caffe中 softmax 函数的前向传播和反向传播
  9. 如何制作BAT(Windows批处理文件)病毒
  10. UC浏览器去广告、联网、升级(支持新版8.1)
  11. 关于Elasticsearch的精确值查找(term)不生效问题
  12. mac 版本charles安装报错-Charles cannot configure your proxy settings while it is on a read-only volume.
  13. 深入浅出ERC777合约
  14. 4月书讯 | 一大波好书来袭,最美华章四月天
  15. SQL注入漏洞-SQL注入原理与实践
  16. Flask项目之手机端租房网站的实战开发(一)
  17. 放开后经济会变好吗?越南是怎样度过的?
  18. 手机端页面 自适应解决方案-收集
  19. STM32学习笔记(13)——模数转换ADC
  20. 最容易上手,也最有用的炒股绝招-3年翻N倍!!

热门文章

  1. Oracle怎样创建共享文件夹,OracleVirtualBox虚拟机如何实现文件夹共享
  2. 锡兰1.1.0现已上市
  3. 儿童汽车拼图游戏 - 儿童游戏拼图2岁-5岁
  4. excel双击后公式计算机,#电脑上的excel表格里的数字为什么要双击才能展开#excel文本双击后变数字...
  5. java 插件 地图_[Java教程]插件~使用ECharts动态在地图上标识点
  6. 大主宰PHP文章,大主宰:沈苍生让李玄通放弃洛璃?牧尘受到眷顾!北溟再出手相助...
  7. 禁止Unity3D中的物体碰撞后旋转
  8. 一、ODI教程--ODI的介绍
  9. mc无可用java_新人求助,MC无法打开,内存java均无问题
  10. Saas 多租户模式介绍