前言
最近在编写一个文本处理软件的时候遇到了字符编码的问题。待写入的文本中出现了很多不常用的字符,例如:’▒’、 ‘▓’、 ‘█’等。这些字符在输出到文本文件后会变成乱码,现在特地将在此过程中的所学及所得总结在下面。
一、常见编码介绍
1. ASCII (American Standard Code for Information Interchange)
ASCII编码字符占用7个Bit,在计算机中占用一个字节,8位,最高位没用,通讯的时候有时用作奇偶校验位。因此ASCII编码的取值范围实际上是:0x00-0x7f,只能表示128个字符。后来发现128个不太够用,做了扩展,叫做ASCII扩展编码,用足八位,取值范围变成:0x00-0xff,能表示256个字符。其实这种扩展意义不大,因为256个字符表示一些非拉丁文字远远不够,但是表示拉丁文字,又用不完。所以扩展的意义还是为了下面的ANSI编码服务。
2. ANSI (American National Standard Institite)
美国国家标准协会,也就是说,每个国家(非拉丁语系国家)自己制定自己的文字的编码规则,并得到了ANSI认可,符合ANSI的标准,全世界在表示对应国家文字的时候都通用这种编码就叫ANSI编码。换句话说,中国的ANSI编码和在日本的ANSI的意思是不一样的,因为都代表自己国家的文字编码标准。比如中国的ANSI对应就是GB2312标准,日本就是JIT标准,香港,台湾对应的是BIG5标准等等。当然这个问题也比较复杂,微软从95开始,用就是自己搞的一个标准GBK。GB2312里面只有6763个汉字,682个符号,所以确实有时候不是很够用。GBK一直能和GB2312相互混淆并且相安无事的一个重要原因是GBK全面兼容GB2312,所以没有出现任何冲突,你用GB2312编码的文件通过GBK去解释一定能获得相同的显示效果,换句话说:GBK对GB2312就是,你有的,我也有,你没得的,我还有!
好了,ANSI的标准是什么呢,首先是ASCII的代码你不能用!也就是说ASCII码在任何ANSI中应该都是相同的。其他的,你们自己扩展。所以呢,中国人就把ASCII码变成8位,0x7f之前我不动你的,我从0xa0开始编,0xa0到0xff才95个码位,对于中国字那简直是杯水车薪,因此,就用两个字节吧,此编码范围就从0xA1A1 - 0xFEFE,这个范围可以表示23901个汉字。基本够用了吧,GB2312才7000多个呢!GBK更猛,编码范围是从0x8140 - 0xFEFE,可以表示3万多个汉字。可以看出,这两种方案,都能保证汉字头一个字节在0x7f以上,从而和ASCII不会发生冲突。能够实现英文和汉字同时显示。
BIG5,香港和台湾用的比较多,繁体,范围: 0xA140 - 0xF9FE, 0xA1A1 - 0xF9FE,每个字由两个字节组成,其第一字节编码范围为0xA1~0xF9,第二字节编码范围为0x40-0x7E与0xA1-0xFE,总计收入13868个字 (包括5401个常用字、7652 个次常用字、7个扩充字、以及808个各式符号)。
那么到底ANSI是多少位呢?这个不一定!比如在GB2312和GBK,BIG5中,是两位!但是其他标准或者其他语言如果不够用,就完全可能不止两位!
例如:GB18030:
GB18030-2000(GBK2K)在GBK的基础上进一步扩展了汉字,增加了藏、蒙等少数民族的字形。GBK2K从根本上解决了字位不够,字形不足的问题。它有几个特点:它并没有确定所有的字形,只是规定了编码范围,留待以后扩充。编码是变长的,其二字节部分与GBK兼容;四字节部分是扩充的字形、字位,其编码范围是首字节0x81-0xfe、二字节0x30-0x39、三字节0x81-0xfe、四字节0x30-0x39。它的推广是分阶段的,首先要求实现的是能够完全映射到Unicode3.0标准的所有字形。它是国家标准,是强制性的。
搞懂了ANSI的含义,我们发现ANSI有个致命的缺陷,就是每个标准是各自为阵的,不保证能兼容。换句话说,要同时显示中文和日本文或者阿拉伯文,就完全可能会出现一个编码两个字符集里面都有对应,不知道该显示哪一个的问题,也就是编码重叠的问题。显然这样的方案不好,所以Unicode才会出现!
3. MBCS(Multi-Byte Chactacter System(Set))
多字节字符系统或者字符集,基于ANSI编码的原理上,对一个字符的表示实际上无法确定他需要占用几个字节的,只能从编码本身来区分和解释。因此计算机在存储的时候,就是采用多字节存储的形式。也就是你需要几个字节我给你放几个字节,比如A我给你放一个字节,比如”中“,我就给你放两个字节,这样的字符表示形式就是MBCS。
在基于GBK的windows中,不会超过2个字节,所以windows这种表示形式有叫做DBCS(Double-Byte Chactacter System),其实算是MBCS的一个特例。C语言默认存放字符串就是用的MBCS格式。从原理上来说,这样是非常经济的一种方式。
4.CodePage
代码页,最早来自IBM,后来被微软,Oracle ,SAP等广泛采用。因为ANSI编码每个国家都不统一,不兼容,可能导致冲突,所以一个系统在处理文字的时候,必须要告诉计算机你的ANSI是哪个国家和地区的标准,这种国家和标准的代号(其实就是字符编码格式的代号),微软称为Codepage代码页,其实这个代码页和字符集编码的意思是一样的。告诉你代码页,本质就是告诉了你编码格式。
但是不同厂家的代码页可能是完全不同,哪怕是同样的编码,比如, UTF-8字符编码 在IBM对应的代码页是1208,在微软对应的是65001,在德国的SAP公司对应的是 4110 。所以啊,其实本来就是一个东西,大家各自为政,搞那么多新名词,实在没必要!所以标准还是很重要的!!!
比如GBK的在微软的代码页是936,告诉你代码页是936其实和告诉你我编码格式是GBK效果完全相同。那么处理文本的时候就不会有问题,不会去考虑某个代码是显示的韩文还是中文,同样,日文和韩文的代码页就和中文不同,这样就可以避免编码冲突导致计算机不知如何处理的问题。当然用这个也可以很容易的切换语言版本。但是这都是治标不治本的方法,还是无法解决同时显示多种语言的问题,所以最后还是都用unicode吧,永远不会有冲突了。
5.Unicode(Universal Code)
这是一个编码方案,说白了就是一张包含全世界所有文字的一个编码表,不管你用的上,用不上,不管是现在用的,还是以前用过的,只要这个世界上存在的文字符号,统统给你一个唯一的编码,这样就不可能有任何冲突了。不管你要同时显示任何文字,都没有问题。因此在这样的方案下,Unicode出现了。Unicode编码范围是:0-0x10FFFF,可以容纳1114112个字符,100多万啊。全世界的字符根本用不完了,Unicode 5.0版本中,才用了238605个码位。所以足够了。
因此从码位范围看,严格的unicode需要3个字节来存储。但是考虑到理解性和计算机处理的方便性,理论上还是用4个字节来描述。
Unicode采用的汉字相关编码用的是《CJK统一汉字编码字符集》— 国家标准 GB13000.1 是完全等同于国际标准《通用多八位编码字符集 (UCS)》 ISO 10646.1。《GB13000.1》中最重要的也经常被采用的是其双字节形式的基本多文种平面。在这65536个码位的空间中,定义了几乎所有国家或地区的语言文字和符号。其中从0x4E00到 0x9FA5 的连续区域包含了 20902 个来自中国(包括台湾)、日本、韩国的汉字,称为 CJK (Chinese Japanese Korean) 汉字。CJK是《GB2312-80》、《BIG5》等字符集的超集。
CJK包含了中国,日本,韩国,越南,香港,也就是CJKVH。这个在UNICODE的Charset chart中可以明显看到。 unicode的相关标准可以从unicode.org上面获得,目前已经进行到了6.0版本。
下面这段描述来自百度百科:
Unicode字符集可以简写为UCS(Unicode Character Set)。早期的 unicodeUnicode标准有UCS-2、UCS-4的说法。UCS-2用两个字节编码,UCS-4用4个字节编码。UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个平面(plane)。每个平面根据第3个字节分为256行 (row),每行有256个码位(cell)。group 0的平面0被称作BMP(Basic Multilingual Plane)。将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。每个平面有2^16=65536个码位。Unicode计划使用了17个平面,一共有17*65536=1114112个码位。在Unicode 5.0.0版本中,已定义的码位只有238605个,分布在平面0、平面1、平面2、平面14、平面15、平面16。其中平面15和平面16上只是定义了两个各占65534个码位的专用区(Private Use Area),分别是0xF0000-0xFFFFD和0x100000-0x10FFFD。所谓专用区,就是保留给大家放自定义字符的区域,可以简写为PUA。 平面0也有一个专用区:0xE000-0xF8FF,有6400个码位。平面0的0xD800-0xDFFF,共2048个码位,是一个被称作代理区Surrogate)的特殊区域。代理区的目的用两个UTF-16字符表示BMP以外的字符。在介绍UTF-16编码时会介绍。如前所述在Unicode 5.0.0版本中,238605-65534*2-6400-2408=99089。余下的99089个已定义码位分布在平面0、平面1、平面2和平面14上,它们对应着Unicode目前定义的99089个字符,其中包括71226个汉字。平面0、平面1、平面2和平面14上分别定义了52080、3419、43253和337个字符。平面2的43253个字符都是汉字。平面0上定义了27973个汉字。
参考资料
彻底搞懂字符编码(unicode,mbcs,utf-8,utf-16,utf-32,big endian,little endian…)
http://blog.csdn.net/wm_1991/article/details/52230716字符串与编码 - 廖雪峰Python教程
http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431664106267f12e9bef7ee14cf6a8776a479bdec9b9000