iconv用法解读
iconv是一个字符集转换函数,原型为:
size_t iconv(iconv_t cd,
             char **inbuf, size_t *inbytesleft,
             char **outbuf, size_t *outbytesleft);
// 传递给do_convert的in_buf,所有字节数(in_buf_size指定)都是可以转换成功的
static int do_convert(iconv_t cd, const char* from, size_t from_size, std::string* to)
{
    char* in_buf_ptr = const_cast<char*>(from);
    size_t in_bytes_left = from_size;
    size_t out_bytes = in_bytes_left*3 + 1;
    size_t out_bytes_left = out_bytes;
    std::string out(out_bytes_left, '\0');
    char* out_buf_start = const_cast<char*>(out.c_str());
    char* out_buf_ptr = out_buf_start;
    int bytes = iconv(cd, &in_buf_ptr, &in_bytes_left, &out_buf_ptr, &out_bytes_left);
    if (-1 == bytes)
        return errno;
    to->assign(out_buf_start, out_bytes-out_bytes_left);
    return 0;
}
// 可忽略不能转换的部分,
// 也可以在结果中保留不能被转换的部分
// 详细实现可以浏览:
// https://github.com/eyjian/mooon/blob/master/common_library/src/utils/charset_utils.cpp
void CCharsetUtils::convert(const std::string& from_charset, const std::string& to_charset,
                            const std::string& from, std::string* to,
                            bool ignore_error, bool skip_error) throw (CException)
{
    std::string result; // 用来保存处理后的内容
    char* in_buf = const_cast<char*>(from.c_str());
    size_t in_bytes = from.size();   // 需要处理的总字节数
    size_t in_bytes_left = in_bytes; // 剩余的未被处理的字节数
    iconv_t cd = iconv_open(to_charset.c_str(), from_charset.c_str());
    if ((iconv_t)(-1) == cd)
    {
        THROW_EXCEPTION(strerror(errno), errno);
    }
    while (in_bytes_left > 0)
    {
        int errcode;
        size_t out_bytes = in_bytes_left * 3 + 1; // 保证足够大
        size_t out_bytes_left = out_bytes;
        std::string out(out_bytes_left, '\0');
        char* out_buf = const_cast<char*>(out.c_str());
        char* out_buf_start = out_buf;
        char* in_buf_start = in_buf;
        // 如果成功,返回值bytes为0
        // 如果成功,in_buf指向in的结尾符,即'\0',同时in_bytes_left值为0
        // 如果失败,in_buf指向未能转换的起始地址,而in_bytes_left值为剩余的未被转换的(可能含有可转换的)字节数
        // 如果成功,则out_bytes-out_bytes_left值为转换后的字节数
        // 如果成功,则out_buf_start存储了被转换后的结果,有效长度为out_bytes-out_bytes_left
        int bytes = iconv(cd, &in_buf, &in_bytes_left, &out_buf, &out_bytes_left);
        if (bytes != -1)
        {
            result.append(out_buf_start, out_bytes-out_bytes_left);
            break;
        }
        else if (!ignore_error)
        {
            errcode = errno;
            iconv_close(cd);
            THROW_EXCEPTION(strerror(errcode), errcode);
        }
        else
        {
            // EILSEQ An invalid multibyte sequence has been encountered in the input.
            // EINVAL An incomplete multibyte sequence has been encountered in the input.
            if ((errno != EINVAL) &&
                (errno != EILSEQ))
            {
                // E2BIG  There is not sufficient room at *outbuf.
                errcode = errno;
                iconv_close(cd);
                THROW_EXCEPTION(strerror(errcode), errcode);
            }
            else
            {
                // in_buf之前部分是可以转换的
                if (in_buf != in_buf_start)
                {
                    std::string str;
                    errcode = do_convert(cd, in_buf_start, in_buf-in_buf_start, &str);
                    if (errcode != 0)
                    {
                        iconv_close(cd);
                        THROW_EXCEPTION(strerror(errcode), errcode);
                    }
                    result.append(str);
                }
                // skip_error决定未能被转换的是否出现在结果当中
                if (!skip_error)
                {
                    result.append(in_buf, 1);
                }
                // 往前推进
                --in_bytes_left; // 将导致while语句结束
                ++in_buf;
            }
        }
    }
    if (-1 == iconv_close(cd))
    {
        THROW_EXCEPTION(strerror(errno), errno);
    }
    // 不能直接使用to,因为to可能就是from
    *to = result;
}
void CCharsetUtils::gbk_to_utf8(const std::string& from, std::string* to, bool ignore_error, bool skip_error) throw (CException)
{
    convert("gbk", "utf-8", from, to, ignore_error, skip_error);
}
void CCharsetUtils::utf8_to_gbk(const std::string& from, std::string* to, bool ignore_error, bool skip_error) throw (CException)
{
    convert("utf-8", "gbk", from, to, ignore_error, skip_error);
}
void CCharsetUtils::gb2312_to_utf8(const std::string& from, std::string* to, bool ignore_error, bool skip_error) throw (CException)
{
    convert("gb2312", "utf-8", from, to, ignore_error, skip_error);
}
void CCharsetUtils::utf8_to_gb2312(const std::string& from, std::string* to, bool ignore_error, bool skip_error) throw (CException)
{
    convert("utf-8", "gb2312", from, to, ignore_error, skip_error);
}iconv用法解读的更多相关文章
- CMake的含义和用法解读
		什么是 CMake 你或许听过好几种 Make 工具,例如 GNU Make ,QT 的 qmake ,微软的 MS nmake,BSD Make(pmake),Makepp,等等.这些 Make 工 ... 
- 学习AngularJs:Directive指令用法
		跟我学AngularJs:Directive指令用法解读(上) http://blog.csdn.net/evankaka/article/details/51232895 跟我学AngularJs: ... 
- const和typedef的常见用法详解
		一.说说const 一般而言,const主要是用来防止定义的对象再次被修改,定义对象变量时要初始化变量. 常见用法如下: 1.用于定义常量变量,这样这个变量在后面就不可以再被修改 const int ... 
- iconv命令
		iconv 用法: Usage: iconv [OPTION...] [FILE...] Convert encoding of given files from one encoding to an ... 
- ralitive absolute
		3.relative与absolute的主要区别: 首先,是上面已经提到过的在正常流中的位置存在与否. 其次,relative定位的层总是相对于其最近的父元素,无论其父元素是何种定位方式.如图3: 图 ... 
- php生成CSV格式(转)
		参考网址: php对csv文件的常用操作集合 http://blog.xhbin.com/archives/748 1,下载CSV格式文档 唯一需要特别注意的是编码. <? include_on ... 
- Linux下windows中文文本文件乱码问题
		table of content: 乱码问题 用gedit选择正确的字符编码打开文件 文件转码 总结 §乱码 Fedora安装时默认用UTF-8字符编码方式, 这么做有国际化的好处(和很多用utf-8 ... 
- PHP iconv()编码转换函数用法示例
		PHP iconv()字符编码转换函数的用法,iconv()函数,在php5中是内置的,语法格式:iconv("UTF- 8","GB2312//IGNORE" ... 
- linux下iconv()函数的用法(转载并修改)
		linux shell 配置文件中默认的字符集编码为UTF-8 .UTF-8是unicode的一种表达方式,gb2312是和unicode都是字符的编码方式,所以说gb2312跟utf-8的概念应该不 ... 
随机推荐
- Git自动换行符
			http://blog.csdn.net/jonathan321/article/details/51988242?locationNum=2 不同的操作系统有不同的换行符格式,跨平台协作时需要考虑版 ... 
- 刷新SQL Server所有视图、函数、存储过程
			刷新SQL Server所有视图.函数.存储过程 更多 sql 此脚本用于在删除或添加字段时刷新相关视图,并检查视图.函数.存储过程有效性. [SQL]代码 --视图.存储过程.函数名称 DE ... 
- 【路由达人】简单两步搞定小米路由新增功能-DDNS(解析域名地址转向在线工具)
			DDNS(Dynamic Domain Name Server)是动态域名服务的缩写! 简单来说目前ISP大多为我们提供动态IP(如ADSL拨号上网),而很多设备或服务需要通过远程访问时需要一个固定的 ... 
- JWPlayer快速入门指南(中文)
			将JW Player嵌入到网页中非常的简单,只需要进行如下3个步骤: 1.解压mediaplayer-viral.zip文件,将jwplayer.js和player.swf文件拷贝到工程中: 2.在页 ... 
- springboot中filter的用法
			一.在spring的应用中我们存在两种过滤的用法,一种是拦截器.另外一种当然是过滤器.我们这里介绍过滤器在springboot的用法,在springmvc中的用法基本上一样,只是配置上面有点区别. 二 ... 
- oracle link的创建过程
			下面做一个测试,在测试中,创建数据库链接的库为XJ(WINDOWS 2003 ORACLE 10g 10.2.0.1),被链接的库为DMDB(LINUX AS5 ORACLE 10g 10.2.0.1 ... 
- 20165233 Java第二、三章学习总结
			2017-2018-2 <Java程序设计>第二周学习总结 教材学习内容总结 第二.三章 ch2 标识符与关键字 基本数据类型: 逻辑类型:boolean 整数类型:int.byte.sh ... 
- 20165233 实验一 Java开发环境的熟悉
			20165233 实验一 Java开发环境的熟悉 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程: 2.完成实验.撰写实验 ... 
- echarts x轴文字显示不全(解决方案)
			echarts x轴标签文字过多导致显示不全 如图: 解决办法1:xAxis.axisLabel 属性 axisLabel的类型是object ,主要作用是:坐标轴刻度标签的相关设置.(当然yAxis ... 
- vs2015 新特性
			vs2015 新特性 自动属性的增强 http://www.kwstu.com/ArticleView/manong_201411200854239378 
