关于字符编码
最近玩因为工作关系被各种编码虐个半死,于是必须总结下,免得以后再才坑。
####unicode
unicode 又名国际码,万国码等,计算机领域业界标准。比如java和python3的内部的string都以unicode表示。
unicode 是一个符号集,仅仅规定了符号的二进制编码,并没有规定如何存储。目前常用的是2字节(16位)的Unicode 即UCS-2,理论上可以表示2^16=65536个字符。
但为了各国字符的扩展,unicode是分区的,也就是说,会划一块远大于他目前字符数量的区域给他用。比如,假设中文目前只有5k个字符,但给他留了1w个空间,这1w个空间就是中文字符区。
所以2个字节的地盘很快就被抢完了,所以就只能继续扩充长度了,一些小语种比如藏文,维语等还有无比蛋疼字符比如\u200b (zero width space character),他们都是三个字节的,最多可以表示2^24个字符。目前三个字节的地盘还没抢完。。。
####utf8
utf8其实是unicode的一种实现,其实是把unicode通过某种规则编码成utf8。
这么做有个好处,可以节省空间,unicode的话UCS-2标准的最小都要占用2个字节,而utf8是可变长的,可以使用1-4个字节表示一个符号
具体编码的详细过程可以参考这里
####汉字编码 GBK, GB2312, GB18030
那么既然unicode,utf-8收录了全世界的汉字,那么为什么还会有GBxxx,台湾有BIG5等各种各自国家专用的编码存在?
嗯,历史原因。
GB2312于1980年制定,然后由wiki发现,Unicode 1.0标准直到1991年10月才发布。于是在这段真空期内世界各地不可能不用计算机啊,既然用的话就肯定有输入本国字符的需要啊,但是由于ASCII的坑已经被占光,(就算不占其实也根本不够用)。于是各国自定的各种编码层出不穷,我国的话就是GBxxx系列了。
GB2312的编码规则:
- 一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,我们还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在 ASCII 里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的”全角”字符,而原来在127号以下的那些就叫”半角”字符了。
可是后来GB2312的字符已经不能满足需要,于是就有了GBK,它包含了GB2312的所有内容,并做了扩展(包括繁体字,符号等),方法是不再要求低字节一定是127号之后的内码,只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。
那个,其实GBK不是国家标准,而是微软标准。。。而GB18030才是国家标准。只不过因为从小用windows系统,所以。。。。
总的来说,GBK和他的子集GB2312都是2个字节表示一个汉字的。
这也是为什么GB系列字符经常被程序员的称呼为双字节字符集 (DBCS)
。
不过后来,随着电脑越来越普及,少数名族同胞也要用电脑了,这么多个民族,这么多种字符,于是乎现有的2字节标准已经不够用了,所以GB18030出现了。
GB18030的特点:
- 共收录汉字70244个
- 与 UTF-8 相同,采用多字节编码,每个字可以由1个、2个或4个字节组成。
- 编码空间庞大,最多可定义161万个字符。
- 支持中国国内少数民族的文字,不需要动用造字区。
- 汉字收录范围包含繁体汉字以及日韩汉字。
GB系列的都有很好的兼容性,旧的系列都是新的系列的子集。
总结
我觉得,其实所谓的各种字符编码其实就是定义了一套规则,一套说明如何将其字符转换成ascii表示的过程和相应的逆过程。
最后举个例子应该就能明白。
1 | u'我').encode('gb18030') unicode( |
因为abc%^&*()
这些符号ascii已经有了,编码后保持不变,所以也就能兼容ascii了。
reference
http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html
http://www.crifan.com/files/doc/docbook/char_encoding/release/html/char_encoding.html#enc_unicode
http://www.phpweblog.net/fuyongjie/archive/2009/03/11/6374.aspx