字符集和编码

字符集和编码--石锅拌饭

 今天被一个python编码问题折腾了半下午。编码问题一直是个让人比較纠结的问题,写这篇文章想简单的总结下python中一些常见的编码问题以及解决方式。这是第一篇,先总结下字符集和编码的一些基本概念和内容。


在编程中经常能够见到各种字符集和编码,包含ASCII,MBCS,Unicode等字符集。确切的说。事实上字符集和编码是两个不同概念,仅仅是有些地方有重合罢了。对于ASCII。MBCS等字符集。基本上一个字符集方案仅仅採用一种编码方案,而对于Unicode。字符集和编码方案是明白区分的。那么先有几个术语须要说明下。以下这段术语说明摘抄自伯乐在线《关于字符编码。你所须要知道的知识》:

  • 字符集(Character Set):顾名思义,就是字符的集合。如ASCII字符集,定义了128个字符,而gb2312定义了7445个字符。

    计算机中字符集的严格定义来说指的是已编号的字符的有序集合(不一定连续)。

  • 字符码(Code Point):指的就是字符集中每一个字符的数字编号。比如ASCII字符集用0-127这连续的128个数字分别表示128个字符。GBK字符集使用区位码的方式为每一个字符编号,首先定义一个94X94的矩阵,行称为“区”,列称为“位”。然后将全部国标汉字放入矩阵其中,这样每一个汉字就能够用唯一的“区位”码来标识了。比如“中”字被放到54区第48位。因此字符码就是5448。

    而Unicode中将字符集依照一定的类别划分到0~16这17个层面(Planes)中。每一个层面中拥有216=65536个字符码,因此Unicode总共拥有的字符码,也即是Unicode的字符空间总共同拥有17*65536=1114112。

  • 字符编码:将字符集中的字符码映射为字节流的一种详细实现方案。比如ASCII字符编码规定使用单字节中低位的7个比特去编码全部的字符。

    比如‘A’的编号是65,用单字节表示就是0×41。因此写入存储设备的时候就是b’01000001’。

    GBK编码则是将区位码(GBK的字符码)中的区码和位码的分别加上0xA0(160)的偏移(之所以要加上这种偏移,主要是为了和ASCII码兼容)。比如刚刚提到的“中”字,区位码是5448。十六进制是0×3630,区码和位码分别加上0xA0的偏移之后就得到0xD6D0,这就是“中”字的GBK编码结果。

  • 代码页(Code Page)一种字符编码详细形式。

    早期字符相对少,因此一般会使用类似表格的形式将字符直接映射为字节流,然后通过查表的方式来实现字符的编解码。现代操作系统沿用了这样的方式。

    比如Windows使用936代码页、Mac系统使用EUC-CN代码页实现GBK字符集的编码,名字尽管不一样。但对于同一汉字的编码肯定是一样的。


1 ASCII

当中ASCII标准本身就规定了字符和字符编码方式,採用单字节编码,总共能够编码128个字符,如空格的编码是32。小写字母a是97,所以ASCII既是字符集又是编码方案。


2 MBCS

对于英文来说,128个符号编码已经够用了,然而对于其它语言比方中文,显然就不够了。

因此就出现了多字节字符集MBCS(Multi-Byte Character Set)。如GB2312,GBK,GB18030,BIG5等编码都属于MBCS。

由于MBCS大都使用2个字节编码,所以有时候也叫DBCS(Double-Byte Character Set)。

我们在Linux系统中看到含有中文的文件编码经常是CP936,那这个事实上就是GBK编码了,这个名字的由来是由于IBM以前发明了一个Code Page的概念,把这些多字节编码收入当中,GBK编码正好位于936页,所以就简称CP936了。


3 Unicode

而后大家认为各种编码太多不方便,不如全部语言字符都使用一套字符集来表示。于是就出现了Unicode。

Unicode/UCS(Unicode Character Set)标准仅仅是一个字符集标准,可是它并没有规定字符的存储和传输方式。

Unicode是一种字符集而不是详细的编码,它主要有3种编码方式:最初Unicode标准使用2个字节表示一个字符。编码方案是UTF-16,还有使用4个字节表示一个字符的编码方案UTF-32。而后来使用英文字符的国家认为不好,原来一个字符存储的如今变成了2个字符。空间增大了一倍,由此UTF-8编码。UTF-8编码中。英文占一个字节,中文占3个字节。


如上面所提到的,Unicode字符集主要採用UTF-8,UTF-16等方式进行编码存储。当然,gbk等字符编码也能够编码Unicode全部的字符集,也算是Unicode的一种字符编码。那么这种话。计算机怎样知道文件採用哪种方式编码呢?Unicode规范中又定义,在每一个文件最前面增加一个表示编码顺序的字符BOM(Byte Order Mark)。比方石锅拌饭中的“石”的UTF-16编码是77F3,採用UTF-16方式存储使用2个字节,一个字节是77,一个字节是F3.存储的时候假设77在前面,F3在后面。则称为big endian方式。反之,则是Little endian方式。。这个字符正好也是2个字节。为FEFF。假设一个文本文件头两个字节威FEFF,则表示採用Big endian方式编码;否则就是Little endian方式。

而UTF-8的BOM是EFBBBF,总结例如以下:

BOM_UTF8 '\xEF\xBB\xBF' 
BOM_UTF16_LE '\xFF\xFE' 
BOM_UTF16_BE '\xFE\xFF'


并非全部的编辑器都会写入BOM。但即使没有BOM,Unicode还是能够读取的,仅仅是须要指定编码,不然可能会失效。


4 ANSI

此外另一种不得不提的是ANSI,ANSI在windows系统中极为常见,事实上ANSI是Windows code pages,这个模式依据当前的locale选定详细编码,假设系统locale是中文简体则採用GBK编码,繁体中文为BIG5编码,日文则是JIS编码。


此外windows中喜欢把BOM_UTF16_LE编码称作Unicode,把BOM_UTF8称作UTF-8。也有人说UTF-8不须要BOM来标示,事实上是不多的。这是由于编辑器一般默认使用UTF-8来測试字符编码而已,假设能够成功解码。就用UTF-8进行解码。即便最開始採用的是ANSI保存的,打开文件时还是最先使用UTF-8来解码。比方你用windows的记事本程序新建一个文件,写入“姹塧”并用ANSI编码保存。再次打开文件,会发现“姹塧”会变成“汉a”。


5 实例分析

还是以石锅拌饭的“石”字来看看在windows以下各种编码方式下的编码吧。

打开windows的记事本程序,分别用ANSI。Unicode(实际是BOM_UTF16_LE),Unicode Big endian。UTF-8这几种编码方式看看终于是否跟之前分析的一样。

这里使用UltraEdit来查看16进制编码,能够打开“编辑”-》16进制编辑功能来查看。


ANSI编码保存,编码是CA AF。这也表示GBK编码存储也採用了Big endian方式。

Unicode编码保存,编码是FF FE F3 77。 

Unicode Big endian编码保存,编码是 FE FF 77 F3。 

UTF-8编码保存。编码是EF BB BF E7 9F B3。


6 參考资料

posted @ 2016-04-13 11:11  mfrbuaa  阅读(378)  评论(0编辑  收藏  举报