博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iconv用法解读
阅读量:5960 次
发布时间:2019-06-19

本文共 3755 字,大约阅读时间需要 12 分钟。

iconv是一个字符集转换函数,原型为:
size_t iconv(iconv_t cd,
             char **inbuf, size_t *inbytesleft,
             char **outbuf, size_t *outbytesleft);
  1. // 传递给do_convert的in_buf,所有字节数(in_buf_size指定)都是可以转换成功的
  2. static int do_convert(iconv_t cd, const char* from, size_t from_size, std::string* to)
  3. {
  4.     char* in_buf_ptr = const_castchar*>(from);
  5.     size_t in_bytes_left = from_size;
  6.     size_t out_bytes = in_bytes_left*3 + 1;
  7.     size_t out_bytes_left = out_bytes;
  8.     std::string out(out_bytes_left, '\0');
  9.     char* out_buf_start = const_castchar*>(out.c_str());
  10.     char* out_buf_ptr = out_buf_start;
  11.     int bytes = iconv(cd, &in_buf_ptr, &in_bytes_left, &out_buf_ptr, &out_bytes_left);
  12.     if (-1 == bytes)
  13.         return errno;
  14.     to->assign(out_buf_start, out_bytes-out_bytes_left);
  15.     return 0;
  16. }
  17. // 可忽略不能转换的部分,
  18. // 也可以在结果中保留不能被转换的部分
  19. // 详细实现可以浏览:
  20. // https://github.com/eyjian/mooon/blob/master/common_library/src/utils/charset_utils.cpp
  21. void CCharsetUtils::convert(const std::string& from_charset, const std::string& to_charset,
  22.                             const std::string& from, std::string* to,
  23.                             bool ignore_error, bool skip_error) throw (CException)
  24. {
  25.     std::string result; // 用来保存处理后的内容
  26.     char* in_buf = const_castchar*>(from.c_str());
  27.     size_t in_bytes = from.size(); // 需要处理的总字节数
  28.     size_t in_bytes_left = in_bytes; // 剩余的未被处理的字节数
  29.     iconv_t cd = iconv_open(to_charset.c_str(), from_charset.c_str());
  30.     if ((iconv_t)(-1) == cd)
  31.     {
  32.         THROW_EXCEPTION(strerror(errno), errno);
  33.     }
  34.     while (in_bytes_left > 0)
  35.     {
  36.         int errcode;
  37.         size_t out_bytes = in_bytes_left * 3 + 1; // 保证足够大
  38.         size_t out_bytes_left = out_bytes;
  39.         std::string out(out_bytes_left, '\0');
  40.         char* out_buf = const_castchar*>(out.c_str());
  41.         char* out_buf_start = out_buf;
  42.         char* in_buf_start = in_buf;
  43.         // 如果成功,返回值bytes为0
  44.         // 如果成功,in_buf指向in的结尾符,即'\0',同时in_bytes_left值为0
  45.         // 如果失败,in_buf指向未能转换的起始地址,而in_bytes_left值为剩余的未被转换的(可能含有可转换的)字节数
  46.         // 如果成功,则out_bytes-out_bytes_left值为转换后的字节数
  47.         // 如果成功,则out_buf_start存储了被转换后的结果,有效长度为out_bytes-out_bytes_left
  48.         int bytes = iconv(cd, &in_buf, &in_bytes_left, &out_buf, &out_bytes_left);
  49.         if (bytes != -1)
  50.         {
  51.             result.append(out_buf_start, out_bytes-out_bytes_left);
  52.             break;
  53.         }
  54.         else if (!ignore_error)
  55.         {
  56.             errcode = errno;
  57.             iconv_close(cd);
  58.             THROW_EXCEPTION(strerror(errcode), errcode);
  59.         }
  60.         else
  61.         {
  62.             // EILSEQ An invalid multibyte sequence has been encountered in the input.
  63.             // EINVAL An incomplete multibyte sequence has been encountered in the input.
  64.             if ((errno != EINVAL) &&
  65.                 (errno != EILSEQ))
  66.             {
  67.                 // E2BIG There is not sufficient room at *outbuf.
  68.                 errcode = errno;
  69.                 iconv_close(cd);
  70.                 THROW_EXCEPTION(strerror(errcode), errcode);
  71.             }
  72.             else
  73.             {
  74.                 // in_buf之前部分是可以转换的
  75.                 if (in_buf != in_buf_start)
  76.                 {
  77.                     std::string str;
  78.                     errcode = do_convert(cd, in_buf_start, in_buf-in_buf_start, &str);
  79.                     if (errcode != 0)
  80.                     {
  81.                         iconv_close(cd);
  82.                         THROW_EXCEPTION(strerror(errcode), errcode);
  83.                     }
  84.                     result.append(str);
  85.                 }
  86.                 // skip_error决定未能被转换的是否出现在结果当中
  87.                 if (!skip_error)
  88.                 {
  89.                     result.append(in_buf, 1);
  90.                 }
  91.                 // 往前推进
  92.                 --in_bytes_left; // 将导致while语句结束
  93.                 ++in_buf;
  94.             }
  95.         }
  96.     }
  97.     if (-1 == iconv_close(cd))
  98.     {
  99.         THROW_EXCEPTION(strerror(errno), errno);
  100.     }
  101.     // 不能直接使用to,因为to可能就是from
  102.     *to = result;
  103. }
  104. void CCharsetUtils::gbk_to_utf8(const std::string& from, std::string* to, bool ignore_error, bool skip_error) throw (CException)
  105. {
  106.     convert("gbk", "utf-8", from, to, ignore_error, skip_error);
  107. }
  108. void CCharsetUtils::utf8_to_gbk(const std::string& from, std::string* to, bool ignore_error, bool skip_error) throw (CException)
  109. {
  110.     convert("utf-8", "gbk", from, to, ignore_error, skip_error);
  111. }
  112. void CCharsetUtils::gb2312_to_utf8(const std::string& from, std::string* to, bool ignore_error, bool skip_error) throw (CException)
  113. {
  114.     convert("gb2312", "utf-8", from, to, ignore_error, skip_error);
  115. }
  116. void CCharsetUtils::utf8_to_gb2312(const std::string& from, std::string* to, bool ignore_error, bool skip_error) throw (CException)
  117. {
  118.     convert("utf-8", "gb2312", from, to, ignore_error, skip_error);
  119. }

转载地址:http://zsyax.baihongyu.com/

你可能感兴趣的文章
linux下git自动补全命令
查看>>
Ubuntu14.04LTS更新源
查看>>
Linux报“Unknown HZ value! (288) Assume 100”错误
查看>>
mysql多实例实例化数据库
查看>>
我的友情链接
查看>>
golang xml和json的解析与生成
查看>>
javascript 操作DOM元素样式
查看>>
Android 内存管理 &Memory Leak & OOM 分析
查看>>
【查找算法】基于存储的查找算法(哈希查找)
查看>>
JavaWeb网上图书商城完整项目--day02-10.提交注册表单功能之页面实现
查看>>
做程序开发的你如果经常用Redis,这些问题肯定会遇到
查看>>
006android初级篇之jni数据类型映射
查看>>
org.openqa.selenium.StaleElementReferenceException
查看>>
HBase 笔记3
查看>>
Linux嵌入式GDB调试环境搭建
查看>>
java分析jvm常用指令
查看>>
【Linux】Linux 在线安装yum
查看>>
Atom 编辑器系列视频课程
查看>>
[原][osgearth]osgearthviewer读取earth文件,代码解析(earth文件读取的一帧)
查看>>
阿里百川码力APP监控 来了!
查看>>