Fork me on GitHub

字符编码

引入

人类在与计算机交互时,用的都是人类能读懂的字符,如中文字符、英文字符、日文字符等,
而计算机只能识别二进制数,详解如下。
二进制数即是由0和1组成的数字。计算机是基于点工作的,电的特性就是高低电频,人类从逻辑层面
将高电频对应为数字1,低电频对应为数字0,这直接决定了计算机可以识别的是由0和1组成的数字。
毫无疑问,由人类的字符到计算机中的数字的,必须经历的过程。
字符------------>翻译------------->数字
翻译的过程必须参照一个特定的标准,该标准称之为字符编码表,该表上存放的就是字符与数字一一
对应的关系。
字符编码中的编码指的是翻译或者转换的意思,即将人能理解的字符翻译成计算机能识别的数字。

1.字符编码发展史

阶段一:一家独大

现代计算机起源于美国,所以最先考虑的仅仅是让计算机识别英文字符,于是诞生了ASCII表
ASCII表的特点:
1、只有英文字符与数字一一对应
2、一个英文字符对应1Bytes,1Bytes=8bit,8bit最多包含256个数字,
可以对应256个字符,足够表示所有的英文字符

阶段二:群雄割据

为了让计算机能够识别中文和英文,中国人定制了GBK
GBK表的特点:
1、只有中文字符、英文字符与数字一一对应关系
2、一个英文字符对应1Bytes
一个中文字符对应2Bytes
补充说明:
1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符
2Bytes=16bit,16bit最多包含65536个数字,可以对应65536个字符,足够表示所有中文字符
每个国家都有各自的字符,为了让计算机能够识别自己国家的字符外加英文字符,各个国家制定了自己的
字符编码表
Shift_JIS表的特点:
1、只有日文字符、英文字符与数字的一一对应关系
Euc-kr表的特点:
1、只有韩文字符、英文字符与数字的一一对应关系
此时,美国人用的计算机里使用字符编码标准是ASCII、中国人用的计算机里使用字符编码标准是GBK、
日本人用的计算机里使用字符编码标准是Shift_JIS,此时的发展就比较混乱。
文件编辑存取文件的原理:
1.存文件文本
人类通过文本编辑器输入的字符会被转化成ASCII格式的二进制存放于内存中,如果需要永久保存,
则直接将ASCII格式的二进制写入硬盘。
2.读文本文件
直接将硬盘中的ASCII格式的二进制读入内存。
此时无论是取还是存所用的字符编码表都是一样,那么肯定不会出现乱码的情况。但是各个国家所用的字符编码表不同,
那么如果在ASCII编码格式的内存中直接输入中文没有GBK翻译则出现乱码,所有不匹配的语言都会出现乱码,
所以我们必须制定一个兼容万国字符的编码表。

阶段三:分久必合

unicode于1990年开始研发,1994年正式公布,具备两大特点:
1.存在所有语言中的所有字符与数字的一一对应关系,即是兼容万国字符
2.余传统的字符编码的二进制数都有关系。
很多地方或老的系统、应用软件仍会采用各种各样的传统的编码,这是历史遗留问题。
软件程序是存放在硬盘中的,要运行软件,则需要将程序加载到内存中,面对硬盘各种传统编码
的软件,想让我们的计算机正常运行且不出现代码,内存中必须要有一个兼容万国的编码,并且该
编码需要与其他编码有相对应的转换关系(识别不同输入字符加识别各种编码的二进制数字,utf-8能识别不同字符,但是不能识别其他编码数字)。
文本编辑器输入任何字符首先是存在于内存中,是直接由unicode编码的,存放于硬盘中,
则可以由其他任意编码表转换成二进制,只要该编码可以支持相应的字符。
英文字符可以被ASCII识别
英文字符--->unciode格式的数字--->ASCII格式的数字
中文字符、英文字符可以被GBK识别
中文字符、英文字符--->unicode格式的数字--->gbk格式的数字
日文字符、英文字符可以被shift-JIS识别
日文字符、英文字符--->unicode格式的数字--->shift-JIS格式的数字
解码与编码:
由字符转换成内存中的unicode,以及由unicode转换成其他编码的过程,都成为编码encode。
由内存中的unicode转换成字符,以及由其他编码转换的成unicode的过程,都称为解码decode。
utf-8的由来
理论上是可以将内存中unicode格式的二进制直接存放于硬盘中的,
但由于unicode固定使用两个字节来存储一个字符,如果多国字符中包含大量的英文字符时,
使用unicode格式存放会额外占用一倍空间(英文字符其实只需要用一个字节存放即可),
然而空间占用并不是最致命的问题,最致命地是当我们由内存写入硬盘时会额外耗费一倍的时间,
所以将内存中的unicode二进制写入硬盘或者基于网络传输时必须将其转换成一种精简的格式,
这种格式即utf-8
那为何在内存中不直接使用utf-8呢?
utf-8是针对Unicode的可变长度字符编码:一个英文字符占1Bytes,一个中文字符占3Bytes,生僻字用更多的Bytes存储
unicode更像是一个过渡版本,我们新开发的软件或文件存入硬盘都采用utf-8格式,等过去几十年,所有老编码的文件都淘汰掉之后,
会出现一个令人开心的场景,即硬盘里放的都是utf-8格式,此时unicode便可以退出历史舞台,内存里也改用utf-8,天下重新归于统一
英文字符------->unciode格式的数字-----ASCII编码--->ASCII二进制
中文字符------->unciode格式的数字-----GBK编码----->GBK二进制
万国字符------->unciode格式的数字-----UTF-8------>UTF-8二进制
在存的时候unciode-----uft-8这条线可以存任何类型的字符,但是取时
uft-8的模式不能解码其他编码格式的二进制,所以会产生乱码。所以在日常使用时,
读取软件需要看编码是否一致。

2.字符编码的应用

1、unicode的作用

内存中固定unicode无论输入任何字符都不会发生乱码

2、乱码问题

我们能够修改的是存取硬盘的编码方式,如果编码设置不正确将会出现乱码。问题分两种:
2.1存乱了:如果用户输入的内容包含中文日文,如果单纯以shift_jis存,日文可以写入,
而中文没有找到对应关系则成为乱码。而且此时已经存在硬盘中不可改了。
2.2读乱了:如果硬盘中的数据是shift_jis格式存储的,采用GBK格式读入就乱了。
总结:
1.保证存的时候不乱:在由内存写入硬盘时,必须将编码格式设置为支持所输入字符的编码格式
2.保证读的时候不乱:在由硬盘读入内存时,必须采用写入硬盘时相同的编码格式

3.python解释器执行文件的三个阶段

执行py文件的前两个阶段就是python解释器读文本文件的过程,与文本编辑读文本文件的前两个阶段没人任何区别,
要保证读不乱码,则必须将python解释器读文件时采用的编码方式设置为文件当初写入硬盘时的编码格式,
如果没有设置,python解释器则才用默认的编码方式,在python3中默认为utf-8,
在python2中默认为ASCII,我们可以通过指定文件头来修改默认的编码
在文件首行写入包含#号在内的以下内容
coding: 当初文件写入硬盘时采用的编码格式
解释器会先用默认的编码方式读取文件的首行内容,由于首行是纯英文组成,
而任何编码方式都可以识别英文字符。
第三个阶段:
设置文件头的作用是保证运行python程序的前两个阶段不乱码,经过前两个阶段后py文件的内容
都会以unicode的格式存放于内存中。在经历第三个阶段时开始识别python语法,但遇到特定的
语法name='上'(代码本身也是由unicode格式存的),需要申请内存空间来存储这个变量,
在python3中,字符串类都是直接使用unicode格式来存储的。
由于Python2的盛行是早于unicode的,因此在Python2中是按照文件头指定的编码来存储字符串类型的值的,
然后再次取用这个值时会按照默认的uft-8的方式去解码,不会产生乱码。但是在cmd指令框中,因为默认编码方式是GBK,所以解码时产生乱码。
(如果文件头中没有指定编码,那么解释器会按照它自己默认的编码方式来存储‘上’),
为了不产生可以在字符串前面加u,则不论头顶的存储方式格式是什么,都是以unicode的方式存储。
这时候可以按照任意方式再去编码,只要支持输入内容的类型,再次解码读取时用同种类型解码到unicode则可直接打印成字符。
与python3方式相同了。

posted @ 2020-09-01 10:41  artherwan  阅读(205)  评论(0编辑  收藏  举报