一、储备知识
引入
字符串类型、文本文件的内容都是由字符组成的,但凡涉及到字符的存取,都需要考虑字符编码的问题。
字符编码的这个知识点的特性就是理论多、结论少,下面就让们来一点点介绍他吧!
三大核心硬件
所有软件都是运行硬件之上的,与运行软件相关的三大核心硬件为CPU、内存、硬盘。我们需要明确三点:
- 运行软件前,软件的代码及其相关数据都是存放于硬盘中的
- 在任何软件的启动都是将数据从硬盘中读入内存,然后CPU从内存中取出指令并执行
- 软件运行过程中产生的数据最先都是存放于内存中的,若想永久保存软件产生的数据,则需要将数据由内存写入硬盘。
文本编辑器读取文件内容的流程
- 启动一个文件编辑器(文本编辑器如nodepad++,pycharm,word)
- 文件编辑器会将文件的内容从硬盘读入内存
- 文本编辑器会将刚刚读入内存的内容显示到屏幕上
python解释器执行文件的流程
- 启动python解释器,此时就相当于启动了一个文本编辑器
- python解释器相当于文本编辑器,从硬盘上将文本内容读入到内存中
- python解释器解释执行刚刚读入内存的内容,开始识别python语法
总结
python解释器与文件文本编辑器的异同如下:
- 相同点:前两个阶段二者完全一样,都是将硬盘中的文件的内容读入内存
- python解释器会解释执行文件内容,因而python解释器具备读py文件的功能,这一点与文本编辑器一样
- 不同点:阶段三时,针对内存读入的内容处理方式不同
- 文本编辑器将文件读入内存后,是为了显示或者编辑,根本不理会python的语法,而python解释器将文件内容读入到内存后,可不是为了给你瞅一眼python代码写的啥,而是为了执行python代码、会识别python语法
二、字符编码介绍
什么是字符编码?
人类与计算机交互时,用的都是人类能读懂的字符,如中文字符、英文字符、日文字符等
而计算机只能识别二进制数。
- 二进制数即由0和1组成的数字,例如
010010101010
。计算机是基于电工作的,电的特性即高低电平,人类从逻辑层面将高电平对应为数字1,低电平对应为数字0,这直接决定了计算机可以识别的是由0和1组成的数字
毫无疑问,由人类的字符到计算机中的数字,必须经历一个过程,如下
- 文字符号=编码(翻译)===>数字
- 文字符号<解码 (翻译)====数字
什么是字符编码表?
就是一张字符与数字对应的关系表
字符编码的发展历史(了解)
字符编码的发展经历了三个重要的阶段,如下
阶段一:一家独大(ASCII)
ASCII表的特点:
- 只有英文字符与数字的一一对应关系
- 一个英文字符对应
1Bytes,1Bytes=8bit
,8bit
最多包含256
个数字,可以对应256个字符,足够表示所有英文字符
阶段二:诸侯割据、天下大乱(ASCII、GBK、Shift-JIS)
为了让计算机能够识别中文和英文,中国人定制了GBK
GBK
表的特点:
-
只有中文字符、英文字符与数字的一一对应关系
-
采用8位二进制数
(1Bytes)
对应一个英文字符,采用16位二进制数(2Bytes)
对应一个中文字符。补充说明: 1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符 2Bytes=16bit,16bit最多包含65536个数字,可以对应65536个字符,足够表示所有中文字符
为让计算机能够识别自己国家的字符外加英文字符,各个国家都制定了自己的字符编码表。此时,美国人用的计算机里使用字符编码标准是ASCII
、中国人用的计算机里使用字符编码标准是GBK
、日本人用的计算机里使用字符编码标准是Shift_JIS
# Shift_JIS表的特点:
1、只有日文字符、英文字符与数字的一一对应关系
# Euc-kr表的特点:
1、只有韩文字符、英文字符与数字的一一对应关系
字符编码发展到了这个阶段,可以用一句话概括:诸侯割据、天下大乱,详解如下
图1中,文本编辑存取文件的原理如下
文本文件内容全都为字符,无论存取都是涉及到字符编码问题
#1、存文本文件
人类通过文本编辑器输入的字符会被转化成ASCII格式的二进制存放于内存中,如果需要永久保存,则直接将内存中的ASCII格式的二进制写入硬盘
#2、读文本文件
直接将硬盘中的ASCII格式的二进制读入内存,然后通过ASCII表反解成英文字符
图2图3都是相同的过程,此时无论是存还是取由于采用的字符编码表一样,所以肯定不会出现乱码问题,但问题是在美国人用的计算机里只能输入英文字符,而在中国人用的计算机里只能输入中文字符和英文字符....,毫无疑问我们希望计算机允许我们输入万国字符均可识别、不乱码,而现阶段计算机采用的字符编码ASCII、GBK、Shift_JIS
都无法识别万国字符,所以我们必须定制一个兼容万国字符的编码表,请看阶段三
阶段三:分久必和unicode
unicode
于1990年开始研发,1994年正式公布,具备两大特点:
- 存在所有语言中的所有字符与数字的一一对应关系,即兼容万国字符
- 与传统的字符编码的二进制数都有对应关系,采用16位二进制数
(2Bytes)
对应一个字符(注意:2个字节无论是对英文还是中文都是对于1个字符),个别生僻字采用4Byets、8Bytes
。详解如下
很多地方或老的系统、应用软件仍会采用各种各样传统的编码,这是历史遗留问题。此处需要强调:软件是存放于硬盘的,而运行软件是要将软件加载到内存的,面对硬盘中存放的各种传统编码的软件,想让我们的计算机能够将它们全都正常运行而不出现乱码,内存中必须有一种兼容万国的编码,并且该编码需要与其他编码有相对应的映射/转换关系,这就是unicode
的第二大特点产生的缘由
文本编辑器输入任何字符都是最新存在于内存中,是unicode
编码的,存放于硬盘中,则可以转换成任意其他编码,只要该编码可以支持相应的字符
# 英文字符可以被ASCII识别
英文字符--->unciode格式的数字--->ASCII格式的数字
# 中文字符、英文字符可以被GBK识别
中文字符、英文字符--->unicode格式的数字--->gbk格式的数字
# 日文字符、英文字符可以被shift-JIS识别
日文字符、英文字符--->unicode格式的数字--->shift-JIS格式的数字
总结,为什么说unicde
是过渡版本?
- 对应万国码
- 最重要的是,也就是说,目前
unicode
主要是争对于老的版本的兼容性,老版本的硬盘中的编码格式慢慢没了,它就没有意义了,这个时候内存就可以使用utf-8
了。
编码与解码(重点)
编码:由字符转换成内存中的unicode
,以及由unicode
转换成其他编码的过程,都称为编码encode
解码:由内存中的unicode
转换成字符,以及由其他编码转换成unicode
的过程,都称为解码decode
在诸多文件类型中,只有文本文件的内存是由字符组成的,因而文本文件的存取也涉及到字符编码的问题
utf-8
的由来
特点:采用8位二进制数(1Bytes)
对应一个英文字符,采用24位二进制数(3Bytes)
对应一个中文字符。
注意:如果保存到硬盘的是GBK
格式二进制,当初用户输入的字符只能是中文或英文,同理如果保存到硬盘的是Shift_JIS
格式二进制,当初用户输入的字符只能是日文或英文……如果我们输入的字符中包含多国字符,那么该如何处理?
#多国字符—淘小欣—》内存(unicode格式的二进制)——淘小欣—》硬盘(GBK格式的二进制)
#多国字符—淘小欣—》内存(unicode格式的二进制)——欣をからかう—》硬盘(Shift_JIS格式的二进制)
#多国字符—淘小欣—》内存(unicode格式的二进制)——淘小欣—》硬盘(???格式的二进制)
理论上是可以将内存中unicode
格式的二进制直接存放于硬盘中的,但由于unicode
固定使用两个字节来存储一个字符,如果多国字符中包含大量的英文字符时,使用unicode
格式存放会额外占用一倍空间(英文字符其实只需要用一个字节存放即可),然而空间占用并不是最致命的问题,最致命地是当我们由内存写入硬盘时会额外耗费一倍的时间,所以将内存中的unicode
二进制写入硬盘或者基于网络传输时必须将其转换成一种精简的格式,这种格式即utf-8
(全称Unicode Transformation Format
,即unicode
的转换格式)
那为何内存中不直接utf-8
呢?
utf-8
是针对Unicode的可变长度字符编码:一个英文字符占1Bytes
,一个中文字符占3Bytes
,生僻字用更多的Bytes
存储
unicode
更像是一个过渡版本,我们新开发的软件或文件存入硬盘都采用utf-8
格式,等过去几十年,所有老编码的文件都淘汰掉之后,会出现一个令人开心的场景,即硬盘里放的都是utf-8
格式,此时unicode
便可以退出历史舞台,内存里也改用utf-8
,天下重新归于统一
总结字符编码:
字符编码对应字符关系:
ASCLL
:只采用1个字节对应一个英文字符GBK
:采用1个字节对应一个英文字符,采用2个字节对应一个中文字符。unicode
:采用2个字节对应一个字符,生僻字采用4个字节、8个字节。(注意:无论是英文还是中文,都是采用2个字符)utf-8
:采用1个字节对应一个英文字符,采用3个字节对应一个中文字符。
目前内存使用的编码:Unicode
-
注意:
unicode
兼容万国码,与万国字符都有对应关系。 -
unicode
有2个作用:1.兼容万国字符
2.兼容万国字符编码表对应关系(
unicode
妥协于此,也就是它目前存在的主要作用)
目前硬盘中使用的编码:utf-8、GBK、Shift-JIS
内存固定使用的Unicode
,我们可以改变的是存入硬盘采用的格式
- 英文+汉字(文本编辑器)=》Unicode(内存)=》GBK(硬盘)
- 英文+日文(文本编辑器)=》Unicode(内存)=》shift-jis(硬盘)
- 王国字符(文本编辑器)=》Unicode(内存)==》utf-8(硬盘)
注意:字符编码之间不可以进行转换。列如:GBK不能转成ASCII,因为这两种字符表的对应关系不一样。但是字符编码之间可以使用unicode作为中间介质,可以进行读写操作。
字符编码的应用
我们学习字符编码就是为了存取字符时不发生乱码问题:
- 内存中固定使用
unicode
无论输入任何字符都不会发生乱码 - 我们能够修改的是存/取硬盘的编码方式,如果编码设置不正确将会出现乱码问题。乱码问题分为两种:存乱了,读乱了
- 存乱了:如果用户输入的内容中包含中文和日文字符,如果单纯以
shift_JIS
存,日文可以正常写入硬盘,而由于中文字符在shift_jis
中没有找到对应关系而导致存乱了 - 读乱了:如果硬盘中的数据是
shift_JIS
格式存储的,采GBK
格式读入内存就读乱了
总结文件存、取乱码问题:
保证存的时候不乱:
- 致命性:存乱了具有致命性,也就是说当你存文件使用的是日文,而你使用
GBK
存入硬盘,这个时候你的硬盘并没有对应这种编码格式,这个时候当你保存存入硬盘重新打开文件,文件内容直接损坏了,数据也就不存在了。 - 解决:在由内存写入硬盘时,你的文件中的字符,必须与存入硬盘所指定的编码格式有所对应。(比如:你使用
GBK
存入硬盘,但是你文件中输入字符是日文,这就不行。因为GBK
只支持中文和英文字符。)
保证读的时候不乱
- 致命性:取乱了并不一定致命,你当初用什么格式存的,那么你就用什么格式取就可以。
- 解决:在由硬盘读入内存时,文件用什么编码格式存入硬盘的,就应该用什么编码格式读入内存。