FireBird的专栏

行之则易

字符编码

1 引言

       任何文字在计算机中都需要编码。由于计算机是由国外引进所以最先有的就是英文字符的编码集即ASCII,之后当然就有了中国汉字的GB2312编码方式,繁体是由BIG5编码。而常见的GBK方式只是GB2312的扩展,通常认为中文字符编码方式为GBK。由上可见,不同文字都有对应的编码方式,非常繁杂,于是乎就有官方制定了统一的格式Unicode编码。需要非常注意的是Unicode只是一种编码方式,即提供的是字符和数字的映射关系,并不提供它的计算机表示实现方式。于是乎就有了UTF-16高尾端、UTF-16低尾端和UTF-8的存储方式。即这三种只是用来计算机存储,它们的“翻译”过程是,计算机编码(UTF-16/UTF-8)到Unicode编码再经过查询文件找到对应的字符。

 

2 ASCII编码

       建立英文字符与二进制的映射关系,用一个字节表示。共规定128个字符编码,存储上占用一个字节的7位,最前面第一位统一为0。[可以作为简单识别的法则]

 

3 GBK编码

       中文字符的编码方式,GBK 亦采用双字节表示,总体编码范围为8140-FEFE,首字节在 81-FE 之间,尾字节在 40-FE 之间,剔除 xx7F 一条线。总计 23940 个码位,共收入 21886 个汉字和图形符号,其中汉字(包括部首和构件)21003 个,图形符号 883 个。

         注意:在Windows中文系统中,如果要将文本另外为其它格式中,提供选择的并没有GBK,这是因为统一成ASCII编码格式,即存储为ASCII编码时,如果文档中有中文字符那么默认会用GBK的方式翻译成二进制数字。

 

4 Unicode编码

       利用三字节甚至更多表示,即建立了三个字节数据到对应字符的映射。如果直接采用三字节存储很明显浪费很多内存。因此有三种实现方式。再次强调只是实现方式,它们都要先翻译成三字节的Unicode编码,然后得到对应的字符。

 

4.1 UTF-16高尾端和UTF-16低尾端

4.1.1 简介

       两者编码方式相似,区别只在于存储的是按高尾端方式存储还是低尾端方式存储。在Windows记事本中另存为“Unicode”是指用UTF-16低尾端格式编码,而“Unicode big endian”是利用UTF16高尾端格式编码。用十六进制显示文本可以发现,UTF16高尾端的前2字节分别是FE FF而UTF16低尾端的前2字节是FF FE。

      注意,这里的16,并不是指仅用2字节存储,16位只是一个单位,当然绝大多数部分2字节够用。具体规则见4.1.2。

4.1.2 编码规则

         [以下摘自百科]

        把Unicode  unicode编码记作U。编码规则如下:

        如果U<0x10000,U的UTF-16编码就是U对应的16位无符号整数(为书写简便,下文将16位无符号整数记作WORD)。

        如果U≥0x10000,计算U'=U-0x10000,然后将U'写成二进制形式:yyyy yyyyyyxx xxxx xxxx,U的UTF-16编码(二进制)就是:1101 10yy yyyy yyyy 1101 11xx xxxx xxxx。为什么U'可以被写成20个二进制位?Unicode的最大码位是0x10ffff,减去0x10000后,U'的最大值是0xfffff,所以肯定可以用20个二进制位表示。

        例如:Unicode编码0x20C30,减去0x10000后,得到0x10C30,写成二进制是:0001 00001100 0011 0000。用前10位依次替代模板中的y,用后10位依次替代模板中的x,就得到:1101100001000011 1101110000110000,即0xD843 0xDC30。 按照上述规则,Unicode编码0x10000-0x10FFFF的UTF-16编码有两个WORD,第一个WORD的高6位是110110,第二个WORD的高6位是110111。可见,第一个WORD的取值范围(二进制)是1101100000000000到11011011 11111111,即0xD800-0xDBFF。第二个WORD的取值范围(二进制)是11011100 00000000到11011111 11111111,即0xDC00-0xDFFF。

4.2 UTF-8

4.2.1 简介

         同样,8并不是只用8位1字节来表示,而是用变长来表示1-4字节表示。它的最大优点在于,1节省内存空间,2兼容ASCII标准。

4.2.2 编码规则

         1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。

        2)对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

        例如“严”的unicode是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(00000800-0000 FFFF),因此“严”的UTF-8编码需要三个字节,即格式是“1110xxxx 10xxxxxx 10xxxxxx”。然后,从“严”的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,“严”的UTF-8编码是 “11100100 10111000 10100101”,转换成十六进制就是E4B8A5。


5 其它

5.1 转换代码

        见参考文献【3】。

5.2 识别方法

        即拿到一个文件如何识别是用何种字符编码而成。分别读取前3字节,如果是0xEF, 0xBB, 0xBF那么该文件编码方式为UTF-8。如果前2字节是0xFF, 0xFE则是UTF16低尾端,如果前2字节是0xFE, 0xFF那么表示的是高尾端,如果都不是,那么肯定存储的是ASCI文件。

        不难发现上述方法并没有区分ASCII和GBK编码,这是因为再者没有交集,而且在Windows中都是存储为ASCI编码。所以如果上述规则都不符合,就认为是ASCI格式。那么对ASCII格式文件的读取方法就不能一字节一字节读取,而是每读一个字节,就分析最高位是否为1,如果为1表示编码为GBK用的是中文字节,所以接着取一个字节,联合在一起去国标码中查找对应字符。如果是0,那么表示的就是英文字符,不继续读取。

5.3 gcc

       在编译文件时,需要注意,GCC中默认源文件和生成文件都是以UTF-8解析和存储的,可以利用如下参数确定。尤其是源文件中含有中文时,特别要注意,最好指定编码集。

-finput-charset=charset  表示源文件的编码方式, 默认以UTF-8来解析

-fexec-charset=charset   表示可执行程序里的字时候以什么编码方式来表示,默认是UTF-8

 

参考文献

[1] http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html

[2] http://blog.sina.com.cn/s/blog_4aa887440101arks.html

[3] http://www.cnitblog.com/wujian-IT/archive/2007/12/13/37671.html

 

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/firstlai/article/details/49933939
想对作者说点什么? 我来说一句

字符 编码 概述

2009年07月24日 41KB 下载

HTML特殊字符编码

2008年11月11日 114KB 下载

java字符编码监听器

2009年09月26日 2KB 下载

ASCII字符编码

2011年09月12日 164KB 下载

HTML特殊字符编码大全

2012年04月12日 33KB 下载

深入理解字符编码

2012年04月23日 286KB 下载

字符编码详情.pdf

2014年12月28日 1004KB 下载

MYSQL字符集与乱码问题分析

2013年09月16日 723KB 下载

没有更多推荐了,返回首页

不良信息举报

字符编码

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭