字符编码(笔记整理)
一、知识储备
三大核心硬件所有软件都是运行硬件之上的,与运行软件相关的三大核心硬件为cpu、内存、硬盘,我们需要明确三点
- 软件运行前,软件的代码及其相关数据都是存放于硬盘中的
- 任何软件的启动都是将数据从硬盘中读入内存,然后cpu从内存中取出指令并执行
- 软件运行过程中产生的数据最先都是存放于内存中的,若想永久保存软件产生的数据,则需要将数据由内存写入硬盘、
1. 文本编辑器读取文件内容的流程
文本编辑器读取文内容的三个阶段阶段1:启动一个文件编辑器(文本编辑器如nodepad++,pycharm,word)
阶段2:文件编辑器会将文件内容从硬盘读入内存
阶段3:文本编辑器会将刚刚读入内存中的内容显示到屏幕上
文本编辑器读取文件内容的大致流程如下:
- 打开文件
用户在编辑器中选择打开文件的操作,此时编辑器会调用操作系统提供的文件打开函数,尝试打开文件并获得该文件的文件句柄。
- 读取文件头
文件打开成功后,编辑器会根据文件类型(如 txt、doc、pdf 等)读取文件头部的一些元数据信息,比如文件编码方式、文件大小等。
- 读取文件内容
编辑器会依次读取文件的内容,读取过程可以分为几个步骤:
(1)确定文件编码:编辑器会根据文件头部的元数据信息确定文件的编码方式,并以相应的方式读取文件内容。
(2)读取文件内容:根据文件编码方式,编辑器会按照规定的字节数一次性读取文件的一部分内容,并将其存储到内存中。
(3)解析和显示内容:读取完文件的一部分内容后,编辑器会对其进行解析,并在编辑器界面上显示出来,供用户查看和编辑。
(4)循环读取:重复执行上述过程,直到读取到文件末尾。
- 处理文件内容
用户在编辑器中对文件进行了修改或其他操作后,编辑器会根据用户操作重新处理文件内容,并保存文件。
- 关闭文件
当用户完成对文件的操作后,编辑器会调用操作系统提供的关闭文件函数,将打开的文件句柄释放,并关闭文件。
总之,编辑器从读取文件头、读取文件内容、解析和显示内容、处理文件内容等多个方面入手,实现了对文本文件的读取和编辑。
2. python解释器执行文件的流程
以python test.py为例,执行流程如下阶段1:启动python解释器,此时就相当于启动了一个文本编辑器
阶段2:python解释器相当于文本编辑器,从硬盘上将test.py的内容读入到内存中
阶段3:python解释器解释执行刚刚读入的内存的内容,开始识别python语法
3. 总结
python解释器与文件本编辑的异同如下
- 相同点:前两个阶段二者完全一致,都是将硬盘中文件的内容读入内存,详解如下
python解释器是解释执行文件内容的,因而python解释器具备读py文件的功能,这一点与文本编辑器一样
- 不同点:在阶段3时,针对内存中读入的内容处理方式不同,详解如下
文本编辑器将文件内容读入内存后,是为了显示或者编辑,根本不去理会python的语法,而python解释器将文件内容读入内存后,可不是为了给你瞅一眼python代码写的啥,而是为了执行python代码、会识别python语法)
二、字符编码介绍
1 什么是字符编码?
人类在与计算机交互时,用的都是人类能读懂的字符,如中文字符、英文字符、日文字符等
而计算机只能识别二进制数,详解如下:
- 二进制数即由0和1组成的数字,例如010010101010。计算机是基于电工作的,电的特性即高低电频,人类从逻辑层面将高电平对应为数字1,低电平对应为数字0,这直接决定了计算机可以识别的是由0和1组成的数字
- 毫无疑问,由人类的字符到计算机中的数字,必须经历一个过程,如下
插图:字符与数字
- 翻译的过程必须参照一个特定的标准,该标准称之为字符编码表,该表上存放的就是字符与数字一一对应的关系。
字符编码中的编码指的是翻译或者转换的意思,即将人能理解的字符翻译成计算机能识别的数字
2. 字符编码表的发展史 (了解)
字符编码的发展经历了三个重要的阶段,如下
阶段一:一家独大现代计算机起源于美国,所以最先考虑仅仅是让计算机识别英文字符,于是诞生了ASCII表
ASCII表的特点:
- 只有英文字符与数字的一一对应关系
- 一个英文字符对应1Bytes,1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符
插图:ascii编码
需要记忆的是:
阶段二:诸侯割据、天下大乱为了让计算机能够识别中文和英文,中国人定制了GBK
GBK表的特点:
- 只有中文字符、英文字符与数字的一一对应关系
- 一个英文字符对应1Bytes
- 一个中文字符对应2Bytes
- 补充说明:
- 1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符
- 2Bytes=16bit,16bit最多包含65536个数字,可以对应65536个字符,足够表示所有中文字符
每个国家都各自的字符,为让计算机能够识别自己国家的字符外加英文字符,各个国家都制定了自己的字符编码表
- Shift_JIS表的特点:只有日文字符、英文字符与数字的一一对应关系
- Euc-kr表的特点:只有韩文字符、英文字符与数字的一一对应关系
此时,美国人用的计算机里使用字符编码标准是ASCII、中国人用的计算机里使用字符编码标准是GBK、日本人用的计算机里使用字符编码标准是Shift_JIS,如下图所示,
插图:各种字符编码
字符编码发展到了这个阶段,可以用一句话概括:诸侯割据、天下大乱,详解如下
图1中,文本编辑存取文件的原理如下
文本文件内容全都为字符,无论存取都是涉及到字符编码问题
1、存文本文件
人类通过文本编辑器输入的字符会被转化成ASCII格式的二进制存放于内存中,如果需要永久保存,则直接将内存中的ASCII格式的二进制写入硬盘
2、读文本文件
直接将硬盘中的ASCII格式的二进制读入内存,然后通过ASCII表反解成英文字符
ASCII图和各种字符编码都是相同的过程,此时无论是存还是取由于采用的字符编码表一样,所以肯定不会出现乱码问题,但问题是在美国人用的计算机里只能输入英文字符,而在中国人用的计算机里只能输入中文字符和英文字符....,毫无疑问我们希望计算机允许我们输入万国字符均可识别、不乱码,而现阶段计算机采用的字符编码ASCII、GBK、Shift_JIS都无法识别万国字符,所以我们必须定制一个兼容万国字符的编码表,请看阶段三
阶段三:分久必合unicode于1990年开始研发,1994年正式公布,具备两大特点:
- 存在所有语言中的所有字符与数字的一一对应关系,即兼容万国字符
- 与传统的字符编码的二进制数都有对应关系,详解如下
很多地方或老的系统、应用软件仍会采用各种各样传统的编码,这是历史遗留问题。此处需要强调:软件是存放于硬盘的,而运行软件是要将软件加载到内存的,面对硬盘中存放的各种传统编码的软件,想让我们的计算机能够将它们全都正常运行而不出现乱码,内存中必须有一种兼容万国的编码,并且该编码需要与其他编码有相对应的映射/转换关系,这就是unicode的第二大特点产生的缘由
文本编辑器输入任何字符都是最新存在于内存中,是unicode编码的,存放于硬盘中,则可以转换成任意其他编码,只要该编码可以支持相应的字符
1.英文字符可以被ASCII识别
英文字符--->unciode格式的数字--->ASCII格式的数字
2.中文字符、英文字符可以被GBK识别
中文字符、英文字符--->unicode格式的数字--->gbk格式的数字
3.日文字符、英文字符可以被shift-JIS识别
日文字符、英文字符--->unicode格式的数字--->shift-JIS格式的数字
3. 编码与解码
编码:是把其他字符串转为二进制的过程
解码:把二进制转为其他字符串的过程
由字符转换成内存中的unicode,以及由unicode转换成其他编码的过程,都称为编码encode
插图:编码
由内存中的unicode转换成字符,以及由其他编码转换成unicode的过程,都称为解码decode
插图:解码
在诸多文件类型中,只有文本文件的内存是由字符组成的,因而文本文件的存取也涉及到字符编码的问题
4. utf-8的由来
注意:如果保存到硬盘的是GBK格式二进制,当初用户输入的字符只能是中文或英文,同理如果保存到硬盘的是Shift_JIS格式二进制,当初用户输入的字符只能是日文或英文……如果我们输入的字符中包含多国字符,那么该如何处理?
- 多国字符—√—》内存(unicode格式的二进制)——X—》硬盘(GBK格式的二进制)
- 多国字符—√—》内存(unicode格式的二进制)——X—》硬盘(Shift_JIS格式的二进制)
- 多国字符—√—》内存(unicode格式的二进制)——√—》硬盘(???格式的二进制)
理论上是可以将内存中unicode格式的二进制直接存放于硬盘中的,但由于unicode固定使用两个字节来存储一个字符,如果多国字符中包含大量的英文字符时,使用unicode格式存放会额外占用一倍空间(英文字符其实只需要用一个字节存放即可),然而空间占用并不是最致命的问题,最致命地是当我们由内存写入硬盘时会额外耗费一倍的时间,所以将内存中的unicode二进制写入硬盘或者基于网络传输时必须将其转换成一种精简的格式,这种格式即utf-8(全称Unicode Transformation Format,即unicode的转换格式)
- 多国字符—√—》内存(unicode格式的二进制)——√—》硬盘(utf-8格式的二进制)
插图:utf-8
那为何在内存中不直接使用utf-8呢:
- utf-8是针对Unicode的可变长度字符编码:一个英文字符占1Bytes,一个中文字符占3Bytes,生僻字用更多的Bytes存储
- unicode更像是一个过渡版本,我们新开发的软件或文件存入硬盘都采用utf-8格式,等过去几十年,所有老编码的文件都淘汰掉之后,会出现一个令人开心的场景,即硬盘里放的都是utf-8格式,此时unicode便可以退出历史舞台,内存里也改用utf-8,天下重新归于统一
三、字符编码的应用
我们学习字符编码就是为了存取字符时不发生乱码问题:
- 内存中固定使用unicode无论输入任何字符都不会发生乱码
- 我们能够修改的是存/取硬盘的编码方式,如果编码设置不正确将会出现乱码问题。乱码问题分为两种:存乱了,读乱了
- 存乱了:如果用户输入的内容中包含中文和日文字符,如果单纯以shift_JIS存,日文可以正常写入硬盘,而由于中文字符在shift_jis中没有找到对应关系而导致存乱了
- 读乱了:如果硬盘中的数据是shift_JIS格式存储的,采GBK格式读入内存就读乱了
总结:
- 保证存的时候不乱:在由内存写入硬盘时,必须将编码格式设置为支持所输入字符的编码格式
- 保证存的时候不乱:在由硬盘读入内存时,必须采用与写入硬盘时相同的编码格式
编码-encode() 方法
Python 中的编码指的是将 Unicode 字符串转换为二进制数据,常用于网络传输和文件存储等场景。
Python 支持多种字符编码格式,如 ASCII 码、UTF-8、GBK 等。
使用字符串对象的encode() 方法,可以将 Unicode 字符串转(编码)为指定格式的二进制
1. str.encode(encoding='UTF-8', errors='strict') #encoding 参数 是指定编码方式(不可修改),默认为 UTF-8;errors 参数指定编码错误处理策略,默认为严格模式
2.例如,将 Unicode 字符串编码为 UTF-8 格式的二进制数据:
s = 'Hello, 世界!'
b = s.encode('utf-8')
print(b)
输出:b'Hello, \xe4\xb8\x96\xe7\x95\x8c!'
解码-**decode() **方法
Python 中的解码指的是将二进制数据还原为 Unicode 字符串,便于进行操作和显示。
使用二进制数据对象的** decode() **方法可以将指定格式的二进制数据转(解码)为 Unicode 字符串
1.bytes.decode(encoding='UTF-8', errors='strict') #encoding 参数指定编码方式,默认为 UTF-8;errors 参数指定编码错误处理策略,默认为严格模式。
2.例如,将 UTF-8 格式的二进制数据解码为 Unicode 字符串:
b = b'Hello, \xe4\xb8\x96\xe7\x95\x8c!'
s = b.decode('utf-8')
print(s)
输出:Hello, 世界!
需要注意的是,在进行编解码时,所使用的字符集必须相同,否则会出现乱码或编解码失败的情况。
示例
下面通过一个示例来演示编码和解码的过程。
假设有一个字符串 s,需要将其写入以 UTF-8 格式编码的文件,并从该文件中读取数据并解码为 Unicode 字符串。
1.将字符串写入文件
with open('test.txt', 'wb') as f:
s = 'Hello, 世界!'
b = s.encode('utf-8')
f.write(b)
2.从文件中读取数据并解码
with open('test.txt', 'rb') as f:
b = f.read()
s = b.decode('utf-8')
print(s)
输出:Hello, 世界!