看透编码问题
我相信,这个问题是所有新手必然面临的困境。
尤其是刚刚接触Linux开发或者网络开发,这个是一个最普遍的问题之一。
一直以来,我也是云里雾里,碰到很多次问题,总是见招拆招,google了事,没有静下心思考一下,总结总结。
正所谓“胸中有丘壑”,才能无敌于天下,所以务必要把这个问题想透。
为了把问题看的更充分,我看了很多资料,其中质量较高或者能引起思考的有以下几个:
1.这篇文章比较全面讲了编码的演化和比较,很好。
http://www.cnblogs.com/KevinYang/archive/2010/06/18/1760597.html
2.这篇是一堆人讨论半天,关于解码和字符集理解的(讨论半天也没有讨论明白..)
http://social.msdn.microsoft.com/Forums/zh-CN/2212/thread/f656ec85-2cd0-4d6a-a207-fe30523cc5a4/
3. 这篇文章很细腻,不妨看看:
http://blog.csdn.net/fancyaphy/article/details/619972
4. 格式比较乱,但是内容还是有不少新意的:
http://blog.chinaunix.net/uid-24245847-id-3228667.html
5.以下这几个是讲python编码,还不错,贴过来。
http://blog.csdn.net/five3/article/details/7030294
http://www.cnblogs.com/mangu-uu/archive/2012/07/04/2575218.html
http://blog.csdn.net/followingturing/article/details/8136973
编码的前世今生,林林总总,我就不粘贴了,前面几个帖子已经说得比较清楚了,我主要归纳一下他们的中心思想:
1. 区分字符集和编码
一般来讲,制定字符的编码标准 = 字符集 + 编码。
字符集是某一种编码所有字符的集合,如GB2312(主要是简体汉字) GBK( 额外加上繁体) GB18030 (额外加上少数民族文字等),全球最大且通用的字符集是Unicode字符集,它试图达到一种全球通用的局面,包含各种语言的字符。
而编码可以理解为物理存储串到字符的一一对应关系。这就涉及到编码(encode)和解码(decode)的问题了。
对应关系呢,GB2312,GBK,GB18030既有字符集的含义,又有字符编码的含义。Unicode呢,有UTF-8,UTF-16等编码方式。
2. 各个编码的整体架构如何呢?
第一阶段:ascii 这个编码只为英文设计
第二阶段:各个国家和地区自行制定编码:ANSI指当地编码,比如在大陆它指GB2312,在台湾它指GBK,日本,阿拉伯,很多很多,彼此各行其政。
第三阶段:考虑全球通用:Unicode是一个通用字符集,在不同环境下可选择UTF-8/UTF-16/UTF-7;
(解决了最要命的问题:同一个文件里,不能共存两种编码的文本)
3.各种编码常见的使用环境是什么呢?
1. 简体中文WIN操作系统,主要是ANSI,简体是GB2312,繁体是BIG5;
2. Linux文件格式一般默认是UTF-8;
4.字符集的包含关系如何呢?
除去各种日语、汉语、阿拉伯语、豪萨语等等不谈,我们只看一下我们能够遇到的:
gb2312 < gbk < gb18030 < unicode. (包含字符在topic1讲过)
前三种,基本算是同一个体系中的,一般可以做到向后兼容。
如果这个想明白,就可以想象:
小字符集转码到大字符集,是没问题的,每个字符都能找到对应的编码。
而大字符集转到小字符集,就可能出现乱码的情况,具体原因简单,不详。
5.浏览器或者编辑器或者终端看到乱码,是怎么回事呢?
我看到论坛里很多人是这样的逻辑:unicode字符集大,我把浏览器调成unicode,应该可以兼容小字符集的gb2312的啊?
此言差矣!
要理解明白:字符集 和编码的区别。
这种乱码问题,跟字符集大小无关,而是“解码器”的问题。browser收到了一个文件,如果是GBK格式的,而采用utf-8的方式解码,读到的就是满篇乱码。同样的物理存储,以不同的解码方式解码,可定会读出各种各样的数据了,当年上学时候学数据结构,应该记得:同样的物理数据,理解成二叉树和普通多叉树是完全可以的,解析方式不同,得到的完全不同的结果。
所以在这个过程总,你要仔细分析:
文本是什么编码的(最初编码方式)?用什么编码传输的(传输协议)?用什么编码读取的(编辑器、终端、浏览器等等)?
6.程序开发我们应该关注什么?
1. 首先要明白这些编码的关系,以及他们通常环境中都用什么编码。
2. 怎么查看编码?怎么转换编码?(关注开发接口)
3. 遇到乱码问题,应该从哪些角度分析?(默认编码/字符集大小等)
7.编码长度问题
gbk,gb2312是采用双字节;
UTF-8是变长编码,英文是单字节,汉字是三字节;
综上,如果文本中大量汉字,gb系列更省空间;如果英文多或者纯英文,自认unicode更佳。
8.编码问题的场景
编码是为了兼容字符集之间的通用性,通常可以编码的地方有:
1、操作系统默认编码
2、程序运行环境的编码 如:终端等
3、源码文件自身的编码 , 这是文件的一个属性
4、程序中的字符串编码 , 这是程序中处理数据的编码。注意和情形3进行区分。
具体来说,就有很多经典场景了,比如 编辑器读写文件的编码,终端显示的编码,数据传输的编码,HTTP协议中关于网页编码的设置,网页中charset的设置,汉字的打印等等。
9.解决编码问题的常用手段
1. 编码检测。通常需要采用一种自动化的方法检测编码,可以利用一些库或者自己分析html头等等。
2. 编码转化 中文问题,通常的情况都是UTF-8 和GB系列之间的转码。有两个情形:
1)编码A 直接转码到 编码B ,典型是php。
2)存在中间编码,需要先转化成中间编码,然后再转成需要的编码。典型是python。decode & encode