引入
字符串类型、本文类型的内容都是由字符组成的,但凡涉及到字符的存取,都需要考虑字符编码的问题
字符编码这个知识点的典型特征就是理论多,结论少,但对于开发而言只需要记住结论即可
知识储备
三大核心硬件
1 2 3 4 5 6
| 所有软件都是运行在硬件之上的,与运行软件相关的三大核心硬件为cpu、内存、硬盘,我们需要明白三点
|

文本编辑器读取文件内容的流程
python解释器执行文件流程
1 2 3 4 5 6 7
| 以python test.py为例,执行流程如下↓↓↓
|
总结
1 2 3 4 5 6 7
| python解释器与文本编辑器的异同如下:
(python解释器是解释执行文件内容的,因而python解释器具备读py文件的功能,这一点与文本编辑器一样)
(文本编辑器将文件内容读入内存后,是为了显示或者编辑,根本不会去理会python语法,而python解释器将文件内容读入内存后,可不是为了给你瞅一眼python代码写的是啥,而是为了执行python代码,会识别python语法)
|
字符编码介绍
什么是字符编码?
1 2 3 4 5 6 7 8 9 10 11 12 13
| 人类再与计算机交互时,用的都是人类能读懂的字符,如中文字符、英文字符、日文字符...
而计算机只能识别二进制数
由人类的字符到计算机中的数字,必须经历一个过程↓↓↓ 字符 ---> 翻译 ---> 数字
翻译的过程必须参照一个特定的标准,该标准称之为字符编码表,该表上存放的就是字符与数字一一对应的关系
字符编码中的编码指的是翻译或者转换的意思是,即将人能理解的字符翻译成计算机能识别的数字
|
字符编码表的发展史(了解)
阶段一:一家独大
1 2 3 4 5
| 现代计算机起源于美国,所以最先考虑的仅仅是让计算机识别英文字符,于是诞生了ASCII表
1 只有英文字符与数字的一一对应关系 2 一个英文字符对应1bytes,1bytes=8bit, 8bit最多包含256个数字,可以对应256个字符,足够表示所有的英文字符
|
阶段二:诸侯割据,天下大乱
1 2 3 4 5 6 7 8
| 为了让计算机能够识别中文和英文,中国人制定了gbk
1 只有中文字符、英文字符与数字的一一对应关系 2 一个英文字符对应1bytes 一个中文字符对应2bytes 补充说明:1bytes = 8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符 2bytes = 16bit,16bit最多包含65536个字符,足够表示所有中文字符
|
1 2 3 4 5 6 7
| 每个国家都有各自的字符(语言),为了让计算能够识别自己国家的字符外加英文字符, 各个国家都制定了自己的字符编码表
1 只有日文字符、英文字符与数字的一一对应关系
1 只有韩文字符、英文字符与数字的一一对应关系
|

1 2 3 4 5 6 7 8 9 10 11 12
| 图1中,文本编辑存取文件的原理如下 文本文件内容全都为字符,无论存取都是涉及到字符编码的问题 人类通过文本编辑器输入的字符会被转换成ASCII格式的二进制存放于内存中,如果需要永久保存,则直接将内存中的ASCII格式的二进制写入硬盘 直接将硬盘中的ASCII格式的二进制读入内存,然后通过ASCII表反解成英文字符 图2图3也都是相同的过程,此时无论是存还是取,由于采用的字符编码表一样,所以肯定不会出现乱码问题,但问题是在美国人用的计算机里只能输入英文字符,而在中国人用的计算机里只能输入中文和英文字符...
毫无疑问我们希望计算机允许我们输入的万国字符均可识别,不乱码,而现阶段计算机采用的字符编码表ASCII、gbk、shift_jis都无法识别万国字符,所以我们必须制定一个兼容万国字符的编码表
|
阶段三:分久必合
1 2 3 4
| Unicode于1990年开始研发,1994年正式公布,具备两大特点:
|
1 2 3
| 很多地方或老的系统、应用软件仍会采用各种各样传统的编码,这是历史遗留问题。此处需要强调:
软件是存放于硬盘的,而运行软件是要将软件加载到内存的,面对硬盘中存放的各种传统编码的软件,想让我们的计算机能够将他们全部正常运行而不出现乱码,内存中必须有一种兼容万国的编码,并且该编码需要与其他编码有相对饮的映射/转换关系,这就是Unicode的第二大特点产生的缘由
|

1 2 3 4 5 6 7 8 9
| 文本编辑器输入任何字符都是最先存于内存中的,而内存是Unicode编码的,若存放于硬盘中,则可以转换成任意其他编码,只要该编码可以支持相应的字符
英文字符 ---> Unicode格式的数字 --->ASCII格式的数字
中文字符、英文字符 ---> Unicode格式的数字 ---> gbk格式的数字
日文字符、英文字符 ---> Unicode格式的数字 ---> shift_JIS格式的数字
|
编码与解码
由字符转换成内存中的Unicode,以及由Unicode转换成其他编码的过程,都称为编码encode

由内存中的Unicode转换成字符,以及由其他编码转换成Unicode的过程,都称为解码decode

utf-8的由来
1 2 3 4 5 6 7 8 9 10 11 12 13
| 注意: 如果保存到硬盘的是gbk格式的二进制,当初用户输入的字符只能是中文或英文,同理,如果保存到硬盘的是shift_JIS格式的二进制,当初用户输入的字符只能是日文或英文,如果我们输入的字符中包含多国字符,那么该如何处理 理论上是可以将内存中Unicode格式的二进制直接存放于硬盘中的,但由于Unicode固定使用两个字节来存储一个字符,如果多国字符中包含大量的英文字符时,使用Unicode格式存放会额外占用一倍空间(英文字符其实只需要用一个字节存放即可),然而空间占用并不是最致命的问题,最致命的问题是当我们由内存写入硬盘时会额外耗费一倍的时间,所以将内存中的Unicode二进制写入硬盘或者基于网络传输时必须将其转换成一种精简的格式,这种格式就是utf-8
|

1 2 3 4
| 那为何不直接在内存中使用utf-8?↓↓↓ utf-8是针对Unicode的可变长度字符编码:一个英文字符占1bytes,一个中文字符占3bytes,生僻字用更多的bytes存储 Unicode更像是一个过渡版本,我们新开发的软件或文件存入硬盘都采用utf-8格式,等过去几十年,所有老编码的文件都淘汰掉之后,会出现一个令人开心的场景,就是硬盘里放的都是utf-8格式,此时Unicode便可以退出历史舞台,内存里也改用utf-8,天下重新归于统一
|
字符编码的应用(重要)
1 2 3 4 5 6 7 8 9
| 我们学习字符编码就是为了存取字符时不发生乱码问题:
|
总结(记):
python解释器执行文件的前两个阶段
1 2 3 4 5
| 执行py文件的前两个阶段就是python解释器读文本文件的过程,与文本编辑读文本文件的前两个阶段没有任何区别, 要保证读不乱码,则必须将python解释器读文件时采用的编码方式设置为文件当初写入硬盘时的编码格式,如果没有设置,python解释器则采用默认的编码方式,在python3中默认为utf-8,在python2中默认ASCII,我们可以通过指定文件头来修改默认的编码方式
--在文件首行写入包含
|
解释器会先用默认的编码方式读取文件的首行内容,由于首行是纯英文组成,而任何编码方式都可以识别英文字符
python解释器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 设置文件头的作用是保证运行python程序的前两个阶段不乱码,经过前两个阶段后py文件的内容都会以Unicode格式存放于内存中 在经历第三个阶段时开始识别python语法,当遇到特定的语法name='上'(代码本身也都全部是Unicode格式存的)时,需要申请内存空间来存储字符串'上',这又涉及到应该以什么编码存储'上'的问题 在python3中,字符串类的值都是使用Unicode格式来存储的 在python2中,由于python2的盛行是早于Unicode的,因此在python2中是按照文件头指定的编码来存储字符串类型的值的(如果文件头中没有指定编码,那么解释器会按照它自己默认的编码方式来存储'上'),所以,这就有可能导致乱码问题
x = '上' print(x)
C:\Users\Administrator>python2 E:\aaa.py 涓
|
字符串encode编码与decode解码的使用
1 2 3 4 5 6 7 8 9 10 11
|
>>> x = '上' >>> res = x.encode('utf-8') >>> res, type(res) (b'\xe4\xb8\x8a', <class 'bytes'>)
# 2 其他编码格式 ------ 解码decode ------> Unicode格式
>>> res.decode('utf-8') '上'
|