字符集和编码
字符集和编码--石锅拌饭
在编程中经常能够见到各种字符集和编码,包含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。