在编程中常常可以见到各种字符集和编码,包括ASCII,MBCS,Unicode等字符集。确切的说,其实字符集和编码是两个不同概念,只是有些地方有重合罢了。对于ASCII,MBCS等字符集,基本上一个字符集方案只采用一种编码方案,而对于Unicode,字符集和编码方案是明确区分的。那么先有几个术语需要说明下,下面这段术语说明摘抄自伯乐在线《关于字符编码,你所需要知道的知识》:
其中ASCII标准本身就规定了字符和字符编码方式,采用单字节编码,总共可以编码128个字符,如空格的编码是32,小写字母a是97,所以ASCII既是字符集又是编码方案。
对于英文来说,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了。
而后大家觉得各种编码太多不方便,不如所有语言字符都使用一套字符集来表示,于是就出现了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还是可以读取的,只是需要指定编码,不然可能会失效。
此外还有一种不得不提的是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”。
还是以石锅拌饭的“石”字来看看在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。