iconv字符编码转换全攻略(转)_iconv强制转换-程序员宅基地

技术标签: C/C++  

网上的高手真的很多,找到的这个文音觉得写的很好,作者博客中还有很多别的写的非常好的东西。
转自: 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之间互相转换的代码写法。

const char* inbuffer; // 输入源,要转换的字符串
int srcLen = strlen(inbuffer);
int outLen = 1024;
static char s_outbuffer[outLen];
memset(s_outbuffer, 0, outLen);
const char* srcStart = inbuffer;
char* tempOutBuffer = s_outbuffer;//要有这个临时变量,否则iconv会直接改写s_outbuffer指针
size_t ret = iconv(cd, (const char**)&srcStart, (size_t *)&srcLen, &tempOutBuffer, (size_t *)&outLen);
iconv_close(cd);

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

FILE* fp = fopen("test-utf16be.txt", "rb"); // 文件是unicode文件,这里要用"rb"来读取,否则有些字节等同于EOF文件会被截断
char srcBuffer[1024] = {0};
fread(srcBuffer, sizeof(srcBuffer) - 1, 1, fp);

// 读取BOM信息
// char x[2];
// fread(&x[0], 1, 1, fp);
// fread(&x[1], 1, 1, fp);

// 带有BOM信息,直接用"utf-16";否则应该特别指定"utf-16le"或是"utf-16be",这个要区分清楚,否则会出现乱码
iconv_t cd = iconv_open("gb18030//TRANSLIT", "utf-16");
int srcLen = 1024;<span style="white-space:pre"> </span>// srcLen和outLen代表的都是字节数,如果是wchar_t就是字符数*sizeof(wchar_t)
int outLen = 1024;
static char s_outbuffer[outLen];
memset(s_outbuffer, 0, outLen);
const char* srcStart = (const char*)srcBuffer;// srcBuffer同样可以是wchar_t,这里也是这样强制转换
char* tempOutBuffer = s_outbuffer;//要有这个临时变量,否则iconv会直接改写s_outbuffer指针
size_t ret = iconv(cd, (const char**)&srcStart, (size_t *)&srcLen, &tempOutBuffer, (size_t *)&outLen);
iconv_close(cd);


最后在再补充一个网上找到的mac os系统下的文本批量转换的命令行方法:
转换文本编码是因为 iPhone 看中文电子书只支持Unicode (UTF-8)。之前有人发了 windows下转换文本编码的软件,就有不少朋友追问苹果系统下的转换软件,甚至有人因此感到讽刺,认为用iPhone 居然是windows 更顺。
        事实是, Mac OS下不需要转换软件,───终端下一行命令就搞定了。
        入正题:
A. 文件名的编码:Mac的文件名本来就用Unicode,所以无须转换在 iPhone就正确显示中文。关键是你传输的工具是否支持Unicode,  譬如Mac 下的Transmit 就支  持unicode,打开Transmit,在 顶栏 > View > Text Encoding > 选择Unicode,这样就支持中文文件名了。
B. 文本内容的编码:用Terminal 里的 iconv 命令批量转换文本编码到UTF8.  步骤:
    1. 新建一个文件夹,这里取 根目录下的文件夹 encoding   ,然后将要转换的文本拉入这个文件夹。
    2. 打开终端,输入以下代码:
     cd /encoding        (回车键)
     find *.txt -exec sh -c "iconv -f GB18030 -t UTF8 {} > {}.txt" \;        (回车键)
    补充:上面的绿色部分是针对GB18030,如果你转换前的编码为GB2312,将 GB18030 代替为 GB2312 即可。
这样就搞定啦。 encoding 文件夹里出现了一批 .txt.txt 扩展名的文本,这些就是转换后的了,拉进iPhone即可。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/fengmm521/article/details/78438687

智能推荐

使用JDBC连接数据库出现 The server time zone value ‘�й���׼ʱ��‘ is unrecognized or represents more than one解决方案_jdbc.properties timezone-程序员宅基地

文章浏览阅读553次。在 jdbc.properties 文件中的 url 后面加上 ?serverTimezone=UTC加入之前的jdbc.properties文件:user=rootpassword=12345678url=jdbc:mysql://localhost:3306/testdriverClass=com.mysql.cj.jdbc.Driver加入之后:user=rootpassword=12345678url=jdbc:mysql://localhost:3306/test?serv_jdbc.properties timezone

计算机图形学孔令德基础知识,计算机图形学基础教程孔令德答案-程序员宅基地

文章浏览阅读1.4k次。计算机图形学基础教程孔令德答案【篇一:大学计算机图形学课程设】息科学与工程学院课程设计任务书题目:小组成员:巴春华、焦国栋成员学号:专业班级:计算机科学与技术、2009级本2班课程:计算机图形学指导教师:燕孝飞职称:讲师完成时间: 2011年12 月----2011年 12 月枣庄学院信息科学与工程学院制2011年12 月20日课程设计任务书及成绩评定12【篇二:计算机动画】第一篇《计算机图形学》..._计算机图形学基础教程 孔令德 答案

python xlwings追加数据_大数据分析Python库xlwings提升Excel工作效率教程-程序员宅基地

文章浏览阅读1k次。原标题:大数据分析Python库xlwings提升Excel工作效率教程Excel在当今的企业中非常非常普遍。在AAA教育,我们通常建议出于很多原因使用代码,并且我们的许多数据科学课程旨在教授数据分析和数据科学的有效编码。但是,无论您偏爱使用大数据分析Python的程度如何,最终,有时都需要使用Excel来展示您的发现或共享数据。但这并不意味着仍然无法享受大数据分析Python的某些效率!实际上,..._xlwings通过索引添加数据

java8u211_jre864位u211-程序员宅基地

文章浏览阅读911次。iefans为用户提供的jre8 64位是针对64位windows平台而开发的java运行环境软件,全称为java se runtime environment 8,包括Java虚拟机、Java核心类库和支持文件,不包含开发工具--编译器、调试器和其它工具。jre需要辅助软件--JavaPlug-in--以便在浏览器中运行applet。本次小编带来的是jre8 64位官方版下载,版本小号u211版..._jre8是什么

kasp技术原理_KASP基因分型-程序员宅基地

文章浏览阅读5k次。KASP基因分型介绍KASP(Kompetitive Allele-Specific PCR),即竞争性等位基因特异性PCR,原理上与TaqMan检测法类似,都是基于终端荧光信号的读取判断,每孔反应都是采用双色荧光检测一个SNP位点的两种基因型,不同的SNP对应着不同的荧光信号。KASP技术与TaqMan法类似,它与TaqMan技术不同的是,它不需要每个SNP位点都合成特异的荧光引物,它基于独特的..._kasp是什么

华为p50预装鸿蒙系统,华为p50会不会预装鸿蒙系统_华为p50会预装鸿蒙系统吗-程序员宅基地

文章浏览阅读154次。华为现在比较火的还真就是新开发的鸿蒙系统了,那么在即将上市的华为p50手机上会不会预装鸿蒙系统呢?接下来我们就来一起了解一下华为官方发布的最新消息吧。1.华为p50最新消息相信大家都知道,随着华为鸿蒙OS系统转正日期临近,似乎全网的花粉们都在关注华为鸿蒙OS系统优化、生态建设等等,直接忽略了不断延期发布的华为P50手机,如今华为P50系列手机终于传来了最新的好消息,在经过一系列方案修改以后,终于被..._华为手机p50直接预装鸿蒙系统

随便推点

python用什么软件编程好-初学python编程,有哪些不错的软件值得一用?-程序员宅基地

文章浏览阅读2.1k次。Python编程的软件其实许多,作为一门面向大众的编程言语,许多修正器都有对应的Python插件,当然,也有特地的PythonIDE软件,下面我简单引见几个不错的Python编程软件,既有修正器,也有IDE,感兴味的朋友可以本人下载查验一下:1.VSCode:这是一个轻量级的代码修正器,由微软规划研发,免费、开源、跨途径,轻盈活络,界面精练,支撑常见的自动补全、语法提示、代码高亮、Git等功用,插..._python入门学什么好

pytorch一步一步在VGG16上训练自己的数据集_torch vgg训练自己的数据集-程序员宅基地

文章浏览阅读3.2w次,点赞30次,收藏307次。准备数据集及加载,ImageFolder在很多机器学习或者深度学习的任务中,往往我们要提供自己的图片。也就是说我们的数据集不是预先处理好的,像mnist,cifar10等它已经给你处理好了,更多的是原始的图片。比如我们以猫狗分类为例。在data文件下,有两个分别为train和val的文件夹。然后train下是cat和dog两个文件夹,里面存的是自己的图片数据,val文件夹同train。这样我们的..._torch vgg训练自己的数据集

毕业论文管理系统设计与实现(论文+源码)_kaic_论文系统设计法-程序员宅基地

文章浏览阅读968次。论文+系统+远程调试+重复率低+二次开发+毕业设计_论文系统设计法

在python2与python3中转义字符_Python 炫技操作:五种 Python 转义表示法-程序员宅基地

文章浏览阅读134次。1. 为什么要有转义?ASCII 表中一共有 128 个字符。这里面有我们非常熟悉的字母、数字、标点符号,这些都可以从我们的键盘中输出。除此之外,还有一些非常特殊的字符,这些字符,我通常很难用键盘上的找到,比如制表符、响铃这种。为了能将那些特殊字符都能写入到字符串变量中,就规定了一个用于转义的字符 \ ,有了这个字符,你在字符串中看的字符,print 出来后就不一定你原来看到的了。举个例子>..._pytyhon2、python3对%转义吗

java jar 文件 路径问题_「问答」解决jar包运行时相对路径问题-程序员宅基地

文章浏览阅读1.3k次。我这几天需要做一个Java程序,需要通过jar的形式运行,还要生成文件。最终这个程序是要给被人用的,可能那个用的人还不懂代码。于是我面临一个问题:生成的文件一定不能存绝对路径。刚开始我想得很简单,打绝对路径改成相对路径不就行了吗?于是有了这样的代码:String path = "../test.txt";File file = new File(path);……这个写法本身并没有问题,直接运行代码..._jar启动文件路径中存在!

微信读书vscode插件_曾经我以为 VSCode 是程序员专属的工具,直到发现了这些……...-程序员宅基地

文章浏览阅读598次。如果你知道 VSCode,一说起它,你可能第一个想到的就是把它当做一个代码编辑器,而它的界面应该可能大概率是这样的——如果你恰好又是个程序员,那你可能经常会用到它,不管是 Python、JS 还是 C++ 等各种语言对应的文件,都可以用它来进行简单的编辑和整理,甚至是运行和 debug......但是今天要讲的显然不是这些,经过小美的多方研究,发现了即使是对于大多数并不了解 VSCode,也完全不..._vscode weixin read