还剩3页未读,继续阅读
文本内容:
字符集编码转换Linuxiconv http://www.gnu,org/software/libiconv/是一个开源的字符编码转换库,可以“方便”的完成几乎所有的编码转换工作
一、字符编码的基本概念
1、ASCH编码,就是英文显示文字所需要的256个字符比如,英文字母、数字、标点符号等等
2、ANSI编码,像中文,肯定不能只用256个字符就代表所有汉字因此对ASCH码表进行了扩展,使用两个或多个字节,代表一个汉字类似的,不同的国家和地区制定了不同的标准,这些使用2个字节来代表一个字符的各种延伸编码方式,称为ANSI编码也就是说,ANSI是一种对ASCH码表进行扩展的泛称,不同语言操作系统,其代表的编码方式不一样比如中文操作系统,ANSI编码就代指GB2312;日文操作系统ANSI编码就代指JIS
3、Unicode编码,Unicode是一个超大的集合,也是一个统一的标准,可以容纳世界上的所有语言符号每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,“汉”这个字的Unicode编码是U+6c
494、代码页codepage,Unicode是一个世界统一的标准,也就是说,如果一个文本是用Unicode方式编码的,那么它可以同时显示中文、日文、阿拉伯文等等,并且是在任何系统上都可以正常显示的但是由于ANSI编码之间互不兼容,因此就需要有一个标识来表明不同的ANSI编码到Unicode之间的映射关系也就是不同编码之间的映射关系,这个就是代码页比如简体中文的代码页是CP_936中文系统默认的代码页,这个也就是windows API中Mu11iByteToWideChar第一个参数所代表的含义如果不标明代码页,系统是不知道如何进行编码转换的
5、SBCS单字节字符集,MBCS多字节字符集,DBCS宽字节字符集,分别对应上面提到的ASCII编码、ANSI编码、Unicode编码
6、中文常见编码GB2312CP_20936-GBK CP_936-GB18030CP_54936,三种编码方式向下兼容,也就是说GB18030包含GB2312的所有字符GB18030在2000年取代GBK成为正式国家标准
7、UCS Unicode Character SetUCS-2规定了2个字节代表一个文字,还有UCS-4规定了4个字节代表一个文字我们工作中几乎总是在和UCS-2打交道注Unicode的学名是〃Universal Multiple-Octet CodedCharacter Set”,简称为UCS.UCS可以看作是“UnicodeCharacterSet〃的缩写
8、UTFUCS TransformationFormatUCS只是规定的如何编码,但是没有规定如何传输、保存这个编码UTF则规定了由几个字节保存这个编码UTF-7,UTF-8,UTF-16都是比较常见的编码方式UTF-8编码与Unicode编码并不相同,但是它们之间可以通过计算进行转换,而不像ANSI和Unicode之间必须通过一个映射表来人为规定其对应关系UTF-16完全对应于UCS-2,并可通过计算代表一部分UCS-4文字还有UTF-32则是完全对应于UCS-4,不过很不常见就是了UTF-8就是在互联网上使用最广的一种unicode的实现方式其他实现方式还包括UTF-16和UTF-32,不过在互联网上基本不用这里的关系是,UTF-8是Unicode的实现方式之一
9、UTF-8是与ASCII码兼容的,英文字母1个字节,汉字通常是3个字节UTF-8的编码规则很简单,只有两条1对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码.因此对于英语字母,UTF-8编码和ASCH码是相同的.2对于n字节的符号nl,第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为
10.剩下的没有提及的二进制位,全部为这个符号的unicode码.符号范围编码方式十六进制|二进制
1.|Unicode|UTF-8-----------------------------------------------------
2.n|
3.—++
4.1|00000000-0000007F|Oxxxxxxx
5.2|00000080-000007FF|I lOxxxxxlOxxxxxx
6.3|00000800-0000FFFF|II lOxxxxlOxxxxxx lOxxxxxxIIIlOxxx lOxxxxxx lOxxxxxx lOxxxxxx
7.4|00010000-0010FFFF|Illi lOxxlOxxxxxx lOxxxxxx lOxxxxxxlOxxxxxx
8.・5|00200000-03FF FFFF|6|04000000-7FFF FFFF|llllllOx lOxxxxxxlOxxxxxxlOxxxxxxlOxxxxxx9lOxxxxxx已知〃严〃的unicode是4E25100111000100101,根据上表,可以发现4E25处在第三行的范围内00000800-0000FFFF,因此〃严〃的UTF-8编码需要三个字节,即格式是〃lllOxxxx lOxxxxxxlOxxxxxx”.然后,从〃严〃的最后一个二进制位开始,依次从后向前填入格式中的X,多出的位补
0.这样就得到了,〃严〃的UTF-8编码是11100100iomoooioiooior,,转换成十六进制就是E4B8A5UTF-16的所有字符都是用2个字节进行保存,其编码与Unicode是等价的UTFT6又分为UTFT6LE littleendian和UTFT6BEbig endian,比如一个字母a,如果按utf-8来存,就是0x61;如果按utf-161e来存就是0x610x00低有效位在前;如果按utf-16be来存就是0x000x61高有效位在前这个也就是我们用记事本另存文件的时候可以选择的几个编码方式的含义第一个字节在前,就是〃大头方式〃Big endian,第二个字节在前就是〃小头方式〃Little endianUnicode规范中定义,每一个文件的最前面分别加入一个表示编码顺序的字符,o这个字符的名字叫做〃零宽度非换行空格〃ZERO WIDTHNO-BREAK SPACE,用FEFF表示.这正好是两个字节,而且FF比FE大
1.//Big EndianFEFF LittleEndianFFFE10BOM byteorder mark,上面提到的utf-8utf-161e utf16-be都是unicode编码,但是系统依然无法正确解析一个文本文件,即便已经知道它是unicode编码所以就有了这样的规定在文本文件的最开头插入几个字节的标识,来说明编码方式utf-8的BOM是Oxef OxbbOxbf,utf-161e的BOM是Oxff Oxfe,utf16-be的BOM是Oxfe Oxffo事实上BOM并不是必须的,它仅仅是帮助程序自动判断编码方式使用的,如果我们手动选择编码方式像ANSI一样,即便没有BOM,也是可以正常显示的反过来说,程序读文本文件的时候要先读文本开始的三个字节判断下编码方式
二、Linux支持的编码转换格式系统终端命令iconv--list或者-1查看iconv命令用于转换指定文件的编码,默认输出到标准输出设备,亦可指定输出文件用法iconv[选项...][文件有如下选项可用输入/输出格式规范-f,--from-code二名称原始文本编码-1,--to-code二名称输出编码信息-1,-list列举所有已知的字符集输出控制-c从输出中忽略无效的字符-o,--output=FILE输出文件-s,—silent关闭警告--verbose打印进度信息-,-help给出该系统求助列表-usage给出简要的用法信息-V,--version打印程序版本号例子iconv-f utf-8-t gb2312aaa.txt bbb.txt这个命令读取aaa.txt文件,从utf-8编码转换为gb2312编码,其输出定向到bbb.txt文件
三、iconv系列函数头文件声明:^include iconv.httinclude stdlib.h
1、iconv_t iconv_open(const char*tocode,const char*fromcode);函数成功返回一个转换描述符(conversion descriptor句柄),失败返I回T,一般是tocode和fromcode的编码不支持导致的如果在tocode后面追加7/TRANSLIT〃(比如〃utf-8〃TRANSLI『),那么如果一个字符无法被转换,则会自动寻找相似字符进行替换如果追加的是〃〃IGNORE〃,则会忽略无法转换的字符
2、size_t iconv(iconv_t cd,const char**inbuf,size_t*inbytesleft,char**outbuf,size_t*outbytesleft);真正用于转换的函数,cd就是iconv_open返回的句柄,要注意,iconv会修改传入的参数,所以要保存好原始utbuf指针转换完毕后inbuf会指向无法成功转换而被截断的第一个字符,inbutesleft顾名思义就是用以记录还未转换的字符数,如果全部转换成功当然就是0了,utbuf指向输出缓存的转换后的字符的末尾,outbutesleft用以记录输出缓冲的剩余空间这个函数有很多细节需要注意如果inbuf中遇到非法字节序列会截断,这时inbuf就指向被截断的第一个字节这种情况一般出现在编码指定错误或者是数据源被截断的时候比如我们指定gb2312转ut-8,但是数据源里出现阿拉伯字符,这个时候就会发生截断如果utbuf空间不足,也会发生截断,不过这种情况相对少见,因为我们程序中会保证输出缓存有足够空间另一种情况相对比较“正常”,就是被转的字符集不包含源字符集的字符,比如utf-8到gb2312的转换就很有可能发生这种情况这时tocode的追加参数就起作用了,iconv会自动进行替换或者忽略如果转换成功(没有发生截断),iconv返回的是不可逆的字符总数(也就是被替换或是忽略的字符总数,如果一切正常,应该返回0),如果转换失败,返回T.注意inbuf和outbuf都必须是有存储空间的不能定义为常量,如char*inbuf二〃abc〃或者是char*outbuf=〃123〃这样定义都是错误的另外inbuf,inbytesleft,outbuf,outbytesleft这几个参数在使用过程中都会改变,最好是先保存一下原值,然后再使用iconv不输出\
03、int iconv_close iconv_t cd;释放句柄资源一示例ttinclude stdio.h#include stdlib.hftinclude string.httinclude iconv.hint mainintargc,char**argv/*目的编码,TRANSLIT遇到无法转换的字符就找相近字符替换*IGNORE遇到无法转换字符跳过*///char*encTo二〃UNICODE〃TRANSLIT〃;char*encTo二〃UNIC0DE〃IGN0RE〃;/*源编码*/char*encFrom=〃UTF-8〃;/*获得转换句柄*@param encTo目标编码方式*@param encFrom源编码方式**/iconv_t cd=iconv_open encTo,encFrom;if cd==iconv_t-lperror〃iconv_open〃;./*需要转换的字符串*/char inbuf
[1024]=abcdef哈哈哈哈行”;size_t srclen=strlen inbuf;/*打印需要转换的字符串的长度*/printf z/srclen=%d\n,z,srclen;/*存放转换后的字符串*/size_t outlen=1024;char outbuf[outlen];memset outbuf,0,outlen;/*由于iconv函数会修改指针,所以要保存源指针*/char*srcstart=inbuf;char*tempoutbuf=outbuf;/*进行转换*@param cdiconv open产生的句柄*@param srcstart需要转换的字符串^@param srclen存放还有多少字符没有转换*@param tempoutbuf存放转换后的字符串*@param outlen存放转换后,tempoutbuf剩余的空间**/size_t ret=iconv cd,srcstart,fesrclen,tempoutbuf,outlen;ifret==-1perror〃iconv;printf/zinbuf=%s,srclen=%d,outbuf=%s,outlen=%d\nz/,inbuf,srclen,outbuf,outlen;int i=0;for i=0;istrlenoutbuf;i++|printf〃%x\n〃,outbuf[i];/*关闭句柄*/iconv_close cd;return0;。
个人认证
优秀文档
获得点赞 0