编码问题的觉悟

  编码问题总是梦魂萦绕地折磨着我。
  即使每次都能找到一个似乎合理的解释来解释这个编码问题,但是实际上自己明 知还是对于整个计算机体系编码问题不能有一个整体的概念,二进制编码/ASCII编码/Unicode/ANSI编码,还有字符串问题等等。

  我们都知道计算机在物理上储存的一切信息,无论是程序还是文件都是以二进制形式存在的。

  因此要明白编码问题不是物理上的问题。

  从百度百科中我们可以知道,计算机文件根本上分为两种文件,一种是文本文件,由一些字符的串行组成的,一般意义上的文本文件格式就是.txt文件。另外一种就是二进制文件即除了文本文件以外的文件,包括我们平时所见的.exe, .jpg, .bmp, .doc, .ppt, .pdf文件。之后我们会提到记事本打开这些文件会出现乱码的问题。

  不说你也可以注意到,文本文件格式打开通过固定的字符编码'翻译'(翻译成字符形式)后,我们轻易就可以进行阅读。而二进制同样也是需要通过相应的应用来'翻译'(翻译成指令)并且'解释'(执行指令)后,只是各种应用翻译和解释方法不同,所以不同文件格式只有通过对应的应用打开才有意义。
  这么来看的话,两者本质其实是可以统一的。文本文件和二进制文件都是以二进制形式储存在计算机硬盘当中,通过相应的应用打开并进行解释,最终的目的都是将计算机的信息转化为人能够理解的信息。

  更为深入来说,文本文件是基于字符编码的文件,而二进制文件是基于值编码的文件。

  对于值编码,我们更容易理解,即根据应用对于二进制值的不同定义的指令来对其进行处理操作。

  而对于字符编码,就是我们常说的ASCII码,Unicode编码,GBK编码等等。确是有些混乱。它们也是对于二进制信息的解释,也就是将二进制信息与各种各样的字符集进行意义匹配,而人们试图在做的就是将二进制信息与全世界各国文字进行一一对应式的匹配。事实上已经在不断地接近了。
  所以也许可以这么来理解,编码其实相当于地址,每次读入二进制信息,或者说读入一堆的二进制地址,之后计算机通过这些地址找出所对应的字符,将字符代替二进制信息显示出来。

  对于统一的一种字符编码,每个字符在具体编码中都是固定的。ASCII编码是8位二进制(bit),即1个字节表示,而Unicode编码(简称UCS)是规定用4个字节的二进制信息来表示,另外还有在记事本中常常看到的ANSI编码相当于是在Unicode编码出现前的对于所有地区不同编码的一种连接,在中文操作系统中ANSI编码就是GBK编码,在日文操作系统中ANSI编码就是日文编码。

  Unicode是国际组织制定的可以容纳世界上所有文字和符号的字符编码方案。Unicode用数字0-0x10FFFF来映射这些字符,最多可以容纳上百万个字符。然而Unicode仅仅是规定了每一个字符对应的二进制代码,但是,首先Unicode没有规定将如何存储这个二进制代码,比如,汉字"严"的unicode是十六进制数4E25,转换成二进制数足足有15位(100111000100101),存储容量就是大问题。其次计算机如何才能判断Unicode和ASCII的不同,因为Unicode可能以三个字节表示一个符号,而若ASCII码是三个字节表示三个符号。
  因此,UTF-8的出现就是解决了这个问题,注意UTF-8是Unicode的一种实现方式,采用可变长度字符编码,长度从1-6个字节,能够实现所有Unicode字符的编码,优点是对于ASCII编码只占一个字节,存储效率较UTF-16等更高。而UTF-16对于绝大多数常用字符,存储空间最小,每个字符只占2个字节。在Windows 2000以后,Windows统一采用UTF-16作为内部字符编码。但目前最常用的是Utf-8。

  我们可以看到记事本支持4种编码格式:ANSI、Unicode、Unicode big endian、UTF-8。其实它们更准确的名称应该是UTF-16LE(Little Endian)、UTF-16BE(Big Endian)和UTF-8,它们是基于Unicode的不同编码方案。这一点之前一直让我混淆unicode和utf8的概念。

  此外还有一个问题,就是关于各个区域原有的编码与Unicode之间的兼容问题。由于Unicode字符集与GBK等字符集并不兼容,所以还需要通过codepage等字符集的映射关系来转化。codepage就是定义了Unicode字符集与GBK等字符集的映射关系。从而实现两者编码的转化问题。

  具体过程: GBK二进制编码 -> GBK字符集 -> codepage -> Unicode字符集 -> UTF-8编码

小结:

  计算机内储存的每一个二进制信息被保存在相应的编码下才有意义。

  编码的作用就是将字符集与二进制信息(编码)一一对应,使得在读取信息和存储信息间能够双向进行。

  Unicode编码包含世界上所有的字符集,每个字符有其对应的二进制信息,但是不适合储存和使用,因此出现了UTF-8作为Unicode编码的一种比较成熟的实现。

参考:

阮一峰:字符编码笔记:ASCII,Unicode和UTF-8

fmddlmyy: GB18030编码研究以及GBK、GB18030与Unicode的映射

linewer[ZZ]Unicode字符编码规范 实例详细介绍各种字符集编码转换问题

附:Python 3 支持编码转换

python 3中的编码默认为utf-8,这样使得python 3甚至能够用中文来表示变量。

  encode([encoding = 'utf-8')])
    编码,也就是将字符编码成相应编码的二进制信息,返回二进制信息,而python 3 默认将其用b''代表二进制信息,其中b代表这是一个二进制信息

  decode([encoding = 'utf-8'])
    解码,将二进制信息利用相应的编码解码成相应的字符串,返回字符串。

无论是任何编码Python将其转换出来的字符串都是Unicode字符集,也就是可以把Unicode字符集看作唯一的字符集,其中攘括了所有的字符。

而关于python 3 编码的转换,就是通过Unicode编码作为中转站获得各种不同编码之间的转化。 

GBK的二进制编码.decode('gbk').encode('utf-8')

  其中decode将GBK的二进制编码解码成GBK字符集并映射到Unicode字符集,后encode将Unicode字符集转换为utf-8的编码。

当然python需要装有相应的编码库比如GBK库才能实现转码。

原文地址:https://www.cnblogs.com/Mathics/p/4046508.html