转自 http://blog.csdn.net/langresser_king/article/details/7459367

iconv(http://www.gnu.org/software/libiconv/)是一个开源的字符编码转换库,可以“方便”的完成几乎所有的编码转换工作。说简单是因为,它常用的接口就三个,iconv_open  iconv   iconv_close,但是即便是只有三个接口,要想使用正确也不容易。这里把一些基本概念和使用细节记录下来,希望能成为一篇最实用的入门教程。
 
一、字符编码基本概念
      更详细的内容可以参考百度百科(http://baike.baidu.com/view/1204863.htm),或是自行google。这里会记录最核心的几个概念。
      1、ASCII编码,就是英文显示文字所需要的256个字符(比如,英文字母、数字、标点符号等等)

2、ANSI编码,像中文,肯定不能只用256个字符就代表所有汉字。因此对ASCII码表进行了扩展,使用两个(或多个)字节,代表一个汉字。类似的,不同的国家和地区制定了不同的标准,这些使用 2 个字节来代表一个字符的各种延伸编码方式,称为 ANSI 编码。也就是说,ANSI是一种对ASCII码表进行扩展的泛称,不同语言操作系统,其代表的编码方式不一样。比如中文操作系统,ANSI编码就代指GB2312;日文操作系统ANSI编码就代指JIS。
      
      3、Unicode编码,Unicode是一个超大的集合,也是一个统一的标准,可以容纳世界上的所有语言符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,“汉”这个字的Unicode编码是U+6C49。

4、代码页(codepage),Unicode是一个世界统一的标准,也就是说,如果一个文本是用Unicode方式编码的,那么它可以同时显示中文、日文、阿拉伯文等等,并且是在任何系统上都可以正常显示的。但是由于ANSI编码之间互不兼容,因此就需要有一个标识来表明不同的ANSI编码到Unicode之间的映射关系(也就是不同编码之间的映射关系),这个就是代码页。比如简体中文的代码页是CP_936(中文系统默认的代码页),这个也就是windows API中MultiByteToWideChar第一个参数所代表的含义。如果不标明代码页,系统是不知道如何进行编码转换的。

5、SBCS(单字节字符集),MBCS(多字节字符集),DBCS(宽字节字符集),分别对应上面提到的ASCII编码、ANSI编码、Unicode编码。

6、中文常见编码:GB2312(CP_20936)->GBK(CP_936)->GB18030(CP_54936),三种编码方式向下兼容,也就是说GB18030包含GB2312的所有字符。GB18030在2000年取代GBK成为正式国家标准。

7、UCS(Unicode Character Set):UCS-2规定了2个字节代表一个文字,还有UCS-4规定了4个字节代表一个文字。我们工作中几乎总是在和UCS-2打交道。

8、UTF(UCS Transformation Format):UCS只是规定的如何编码,但是没有规定如何传输、保存这个编码。UTF则规定了由几个字节保存这个编码。UTF-7,UTF-8,UTF-16都是比较常见的编码方式。UTF-8编码与Unicode编码并不相同,但是它们之间可以通过计算进行转换,而不像ANSI和Unicode之间必须通过一个映射表来人为规定其对应关系。UTF-16完全对应于UCS-2,并可通过计算代表一部分UCS-4文字。还有UTF-32则是完全对应于UCS-4,不过很不常见就是了。

9、UTF-8是与ASCII码兼容的,英文字母1个字节,汉字通常是3个字节;UTF-16的所有字符都是用2个字节进行保存,其编码与Unicode是等价的。UTF-16又分为UTF-16LE(little endian)和UTF-16BE(big endian),比如一个字母'a',如果按utf-8来存,就是0x61;如果按utf-16le来存就是0x61 0x00(低有效位在前);如果按utf-16be来存就是0x00 0x61(高有效位在前)。这个也就是我们用记事本另存文件的时候可以选择的几个编码方式的含义。

10、BOM(byte order mark),上面提到的utf-8 utf-16le utf16-be都是unicode编码,但是系统依然无法正确解析一个文本文件,即便已经知道它是unicode编码。所以就有了这样的规定:在文本文件的最开头插入几个字节的标识,来说明编码方式。utf-8的BOM是0xef 0xbb 0xbf,utf-16le的BOM是0xff 0xfe,utf16-be的BOM是0xfe 0xff。事实上BOM并不是必须的,它仅仅是帮助程序自动判断编码方式使用的,如果我们手动选择编码方式(像ANSI一样),即便没有BOM,也是可以正常显示的。反过来说,程序读文本文件的时候要先读文本开始的三个字节判断下编码方式。

二、iconv支持的编码格式:

European languages
ASCII, ISO-8859-{1,2,3,4,5,7,9,10,13,14,15,16}, KOI8-R, KOI8-U, KOI8-RU, CP{1250,1251,1252,1253,1254,1257}, CP{850,866,1131}, Mac{Roman,CentralEurope,Iceland,Croatian,Romania}, Mac{Cyrillic,Ukraine,Greek,Turkish}, Macintosh
Semitic languages
ISO-8859-{6,8}, CP{1255,1256}, CP862, Mac{Hebrew,Arabic}
Japanese
EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP, ISO-2022-JP-2, ISO-2022-JP-1
Chinese
EUC-CN, HZ, GBK, CP936, GB18030, EUC-TW, BIG5, CP950, BIG5-HKSCS, BIG5-HKSCS:2004, BIG5-HKSCS:2001, BIG5-HKSCS:1999, ISO-2022-CN, ISO-2022-CN-EXT
Korean
EUC-KR, CP949, ISO-2022-KR, JOHAB
Armenian
ARMSCII-8
Georgian
Georgian-Academy, Georgian-PS
Tajik
KOI8-T
Kazakh
PT154, RK1048
Thai
ISO-8859-11, TIS-620, CP874, MacThai
Laotian
MuleLao-1, CP1133
Vietnamese
VISCII, TCVN, CP1258
Platform specifics
HP-ROMAN8, NEXTSTEP
Full Unicode
UTF-8 
UCS-2, UCS-2BE, UCS-2LE 
UCS-4, UCS-4BE, UCS-4LE 
UTF-16, UTF-16BE, UTF-16LE 
UTF-32, UTF-32BE, UTF-32LE 
UTF-7 
C99, JAVA
Full Unicode, in terms of uint16_t or uint32_t (with machine dependent endianness and alignment)
UCS-2-INTERNAL, UCS-4-INTERNAL
Locale dependent, in terms of `char' or `wchar_t' (with machine dependent endianness and alignment, and with OS and locale dependent semantics)
char, wchar_t 
The empty encoding name "" is equivalent to "char": it denotes the locale dependent character encoding.

When configured with the option --enable-extra-encodings, it also provides support for a few extra encodings:

European languages
CP{437,737,775,852,853,855,857,858,860,861,863,865,869,1125}
Semitic languages
CP864
Japanese
EUC-JISX0213, Shift_JISX0213, ISO-2022-JP-3
Chinese
BIG5-2003 (experimental)
Turkmen
TDS565
Platform specifics
ATARIST, RISCOS-LATIN1

通过第一部分的讲解,这些编码格式应该看着比较清晰了。比如gb2312-->unicode的转化就是GBK(或者是gb18030  cp936,我们之前说过,大多数情况这些是等价的)到ucs-2(或者是utf-16,如果文本信息中没有BOM就要特别指定utf-16le或是utf-16be)的转化。这些就是我们将要用到的编码转换的参数。

三、iconv函数详解

1、iconv_t iconv_open (const char* tocode, const char* fromcode);

如果转换编码不支持(通常是写错了),那么就返回-1,否则返回一个句柄。tocode和fromcode传的就是上面列表中的参数。补充,如果在tocode后面追加"//TRANSLIT"(比如"utf-8//TRANSLIT"),那么如果一个字符无法被转换,则会自动寻找相似字符进行替换。如果追加的是"//IGNORE",则会忽略无法转换的字符。

2、size_t iconv (iconv_t cd,
const char* *
inbuf, size_t * inbytesleft,
char* *
outbuf, size_t * outbytesleft);

真正用于转换的函数,cd就是iconv_open返回的句柄,要注意,iconv会修改传入的参数,所以要保存好原始outbuf指针。转换完毕后inbuf会指向无法成功转换而被截断的第一个字符,inbutesleft顾名思义就是有多少字符尚未转换,如果全部转换成功当然就是0了,outbuf指向输出缓存的转换后的字符的末尾,outbutesleft表明输出缓存尚有多少自己剩余。
这个函数有很多细节需要注意。如果inbuf中遇到非法字节序列会截断,这时inbuf就指向被截断的第一个字节。这种情况一般出现在编码指定错误或者是数据源被截断的时候。比如我们指定gb2312转ut-8,但是数据源里出现阿拉伯字符,这个时候就会发生截断。          如果outbuf空间不足,也会发生截断,不过这种情况相对少见,因为我们程序中会保证输出缓存有足够空间。
       另一种情况相对比较“正常”,就是被转的字符集不包含源字符集的字符,比如utf-8到gb2312的转换就很有可能发生这种情况。这时tocode的追加参数就起作用了,iconv会自动进行替换或者忽略。
       如果转换成功(没有发生截断),iconv返回的是不可逆的字符总数(也就是被替换或是忽略的字符总数,如果一切正常,应该返回0),如果转换失败,返回-1.

3、int iconv_close (iconv_t cd);

释放句柄资源。

四、utf-8-->gb18030转换示例
    这个代表了ansi和utf-8或者是ansi之间互相转换的代码写法。

  1. <span style="font-size:16px;">iconv_t cd = iconv_open("gb18030//TRANSLIT", "<span style="font-family: Georgia; ">utf-8</span>");
  2. const char* inbuffer; // 输入源,要转换的字符串
  3. int srcLen = strlen(inbuffer);
  4. int outLen = 1024;
  5. static char s_outbuffer[outLen];
  6. memset(s_outbuffer, 0, outLen);
  7. const char* srcStart = inbuffer;
  8. char* tempOutBuffer = s_outbuffer;//要有这个临时变量,否则iconv会直接改写s_outbuffer指针
  9. size_t ret = iconv(<span style="font-family:Georgia;">cd</span>, (const char**)&srcStart, (size_t *)&srcLen, &tempOutBuffer, (size_t *)&outLen);
  10. iconv_close(cd);
  11. </span>

五、unicode->gb18030转换示例
      这个代表了宽字符和多字节之间的转换,也就是wchar_t和char之间的转换,也就是WideCharToMultiByte所完成的操作。

    1. FILE* fp = fopen("test-utf16be.txt", "rb"); // 文件是unicode文件,这里要用"rb"来读取,否则有些字节等同于EOF文件会被截断
    2. char srcBuffer[1024] = {0};
    3. fread(srcBuffer, sizeof(srcBuffer) - 1, 1, fp);
    4. // 读取BOM信息
    5. // char x[2];
    6. // fread(&x[0], 1, 1, fp);
    7. // fread(&x[1], 1, 1, fp);
    8. // 带有BOM信息,直接用"utf-16";否则应该特别指定"utf-16le"或是"utf-16be",这个要区分清楚,否则会出现乱码
    9. iconv_t cd = iconv_open("gb18030//TRANSLIT", "utf-16");
    10. int srcLen = 1024;<span style="white-space:pre">    </span>// srcLen和outLen代表的都是字节数,如果是wchar_t就是字符数*sizeof(wchar_t)
    11. int outLen = 1024;
    12. static char s_outbuffer[outLen];
    13. memset(s_outbuffer, 0, outLen);
    14. const char* srcStart = (const char*)srcBuffer;// srcBuffer同样可以是wchar_t,这里也是这样强制转换
    15. char* tempOutBuffer = s_outbuffer;//要有这个临时变量,否则iconv会直接改写s_outbuffer指针
    16. size_t ret = iconv(cd, (const char**)&srcStart, (size_t *)&srcLen, &tempOutBuffer, (size_t *)&outLen);
    17. iconv_close(cd);

iconv字符编码转换的更多相关文章

  1. php 字符编码转换函数 iconv mb_convert_encoding比较

    在使用PHP处理字符串时,我们经常会碰到字符编码转换的问题,你碰到过iconv转换失败吗? 发现问题时,网上搜了搜,才发现iconv原来有bug ,碰到一些生僻字就会无法转换,当然了配置第二个参数时, ...

  2. iconv 文件编码转换

    iconv 文件编码转换 http://www.cnblogs.com/xuxm2007/archive/2010/11/09/1872379.html 查看iconv的支持的编码: $ iconv  ...

  3. 编码问题 php字符编码转换类

    各种平台和软件打开显示的编码问题,需要使用不同的编码,根据我们不同的需求. php 字符编码转换类,支持ANSI.Unicode.Unicode big endian.UTF-8.UTF-8+Bom ...

  4. php字符编码转换之gb2312转为utf8(转)

    在php中字符编码转换我们一般会用到iconv与mb_convert_encoding进行操作,但是mb_convert_encoding在转换性能上比iconv要差很多哦.string iconv ...

  5. erlang中字符编码转换(转)

    转自:http://www.thinksaas.cn/group/topic/244329/ 功能说明: erlang中对各种语言的编码支持不足,此代码是使用erlang驱动了著名的iconv编码库来 ...

  6. Char Tools,方便的字符编码转换小工具

    工作关系,常有字符编码转换方面的需要,写了这个小工具 Char Tools是一款方便的字符编码转换小工具,基于.Net Framework 2.0 Winform开发 主要功能 URL编码:URLEn ...

  7. Python—字符编码转换、函数基本操作

    字符编码转换 函数 #声明文件编码,格式如下: #-*- coding:utf-8 -*- 注意此处只是声明了文件编码格式,python的默认编码还是unicode 字符编码转换: import sy ...

  8. day4学python 字符编码转换+元组概念

    字符编码转换+元组概念 字符编码转换 #coding:gbk //此处必声明 文件编码(看右下角编码格式) #用来得到python默认编码 import sys print(sys.getdefaul ...

  9. php iconv实现编码转换

    php iconv实现编码转换 <pre><?php $content = iconv('GB2312', 'UTF-8//IGNORE', $content); ?> < ...

随机推荐

  1. poj 1185

    上一题的升级版 dp[i][j][k] 表示第 i 行状态为 k 第i-1行状态为 j #include <cstdio> #include <cstdlib> #includ ...

  2. Android 4.4 KitKat, the browser and the Chrome WebView

    Having V8 as the JavaScript engine for the new web view, the JavaScript performance if much better, ...

  3. Sqli-labs less 35

    Less-35 35关和33关是大致的一样的,唯一的区别在于sql语句的不同. $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1"; ...

  4. POJ 2674

    Linear world Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 2448   Accepted: 564 Descr ...

  5. awk处理之案例二:awk匹配文本

    编译环境 本系列文章所提供的算法均在以下环境下编译通过. [脚本编译环境]Federa 8,linux 2.6.35.6-45.fc14.i686 [处理器] Intel(R) Core(TM)2 Q ...

  6. 定时每天执行前一天的数据导入oracle

    #!/bin/bash export LANG="en_US.UTF-8" #设定时间变量,为前一天时间 log_date=`date +%Y-%m-%d -d "-1 ...

  7. linux下对普通用户设置文件访问控命令之setfacl

    命令名 setfacl  -设置文件访问控制列表 常用用法:setfacl [-bkRd] [{-m|-x} acl参数] 目标文件名 命令的常用参数 -m 设置后续的acl参数给文件使用(常用). ...

  8. vim中如何引用自定义模板文件

    我们在使用vim新建文件时可以引用自定义模板,来避免重复的数据格式处理花费太多时间. 实现方法很简单,只需要2步即可:1. 在.vim/template目录放入自己的模板文件(如shellconfig ...

  9. CSS3做小三角形

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXgAAAA2CAIAAABC2hVZAAAgAElEQVR4nKzcd3cbV57web+1p20FW8

  10. C语言学习资料(转载)

    ◆经典C源程序100例:http://post.baidu.com/f?kz=8618367 ◆时钟的驻留程序:http://post.baidu.com/f?kz=10822377 ◆数据结构暨若干 ...