python之字符编码、存取文件乱码问题、python2字符串乱码问题

一、文本编辑器存取文件的原理(nodepad++,pycharm,word)

#1、打开编辑器就打开了启动了一个进程,是在内存中的,所以,用编辑器编写的内容也都是存放与内存中的,断电后数据丢失

#2、要想永久保存,需要点击保存按钮:编辑器把内存的数据刷到了硬盘上。

#3、在我们编写一个py文件(没有执行),跟编写其他文件没有任何区别,都只是在编写一堆字符而已。

三、python解释器执行py文件的原理 ,例如python test.py

#第一阶段:python解释器启动,此时就相当于启动了一个文本编辑器

#第二阶段:python解释器相当于文本编辑器,去打开test.py文件,从硬盘上将test.py的文件内容读入到内存中(小复习:pyhon的解释性,决定了解释器只关心文件内容,不关心文件后缀名)

#第三阶段:python解释器解释执行刚刚加载到内存中test.py的代码( ps:在该阶段,即真正执行代码时,才会识别python的语法,执行文件内代码,当执行到name="egon"时,会开辟内存空间存放字符串"egon")

四、python解释器与文件本编辑的异同

#1、相同点:python解释器是解释执行文件内容的,因而python解释器具备读py文件的功能,这一点与文本编辑器一样

#2、不同点:文本编辑器将文件内容读入内存后,是为了显示或者编辑,根本不去理会python的语法,而python解释器将文件内容读入内存后,可不是为了给你瞅一眼python代码写的啥,而是为了执行python代码、会识别python语法。

五、什么是字符编码?

很明显,我们平时在使用计算机时,用的都是人类能读懂的字符(用高级语言编程的结果也无非是在文件内写了一堆字符),如何能让计算机读懂人类的字符?

 必须经过一个过程:
  #字符--------(翻译过程)------->数字 

  #这个过程实际就是一个字符如何对应一个特定数字的标准,这个标准称之为字符编码

六、 以下两个场景下涉及到字符编码的问题

#1、一个python文件中的内容是由一堆字符组成的,存取均涉及到字符编码问题(python文件并未执行,前两个阶段均属于该范畴)

#2、python中的数据类型字符串是由一串字符组成的(python文件执行时,即第三个阶段)

七、字符编码的发展史与分类

1、历史演变


阶段一:现代计算机起源于美国,最早诞生也是基于英文字符考虑的ASCII


ASCII码采用8位(1byte)进行编码

ASCII:一个Bytes代表一个字符(英文字符/键盘上的所有其他字符),1Bytes=8bit,8bit可以表示0-2**8-1种变化,即可以表示256个字符

ASCII最初只用了后七位,127个数字,已经完全能够代表键盘上所有的字符了(英文字符/键盘的所有其他字符),后来为了将拉丁文也编码进了ASCII表,将最高位也占用了

阶段二:为了满足中文和英文,中国人定制了GBK


GBK中文采用16位进行编码,英文还是采用8位编码

GBK:2Bytes代表一个中文字符,1Bytes表示一个英文字符
为了满足其他国家,各个国家纷纷定制了自己的编码
日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里

阶段三:各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。如何解决这个问题呢???


unicode全部都采用16位编码,utf-8对英文字符只用1Bytes表示,对中文字符用3Bytes,对其他生僻字用更多的Bytes去存

#!!!!!!!!!!!!非常重要!!!!!!!!!!!!
说白了乱码问题的本质就是不统一,如果我们能统一全世界,规定全世界只能使用一种文字符号,然后统一使用一种编码,那么乱码问题将不复存在,
ps:就像当年秦始皇统一中国一样,书同文车同轨,所有的麻烦事全部解决
很明显,上述的假设是不可能成立的。很多地方或老的系统、应用软件仍会采用各种各样的编码,这是历史遗留问题。于是我们必须找出一种解决方案或者说编码方案,需要同时满足:
#1、能够兼容万国字符
#2、与全世界所有的字符编码都有映射关系,这样就可以转换成任意国家的字符编码

这就是unicode(定长), 统一用2Bytes代表一个字符, 虽然2**16-1=65535,但unicode却可以存放100w+个字符,因为unicode存放了与其他编码的映射关系,准确地说unicode并不是一种严格意义上的字符编码表,下载pdf来查看unicode的详情:
链接:https://pan.baidu.com/s/1dEV3RYp

很明显对于通篇都是英文的文本来说,unicode编码采用16位编码完全就是增大了磁盘IO开销、延时(二进制最终都是以电或者磁的方式存储到存储介质中的)

于是产生了UTF-8(可变长,全称Unicode Transformation Format),对英文字符只用1Bytes表示,对中文字符用3Bytes,对其他生僻字用更多的Bytes去存

#总结:内存中统一采用unicode,浪费空间来换取可以转换成任意编码(不乱码),硬盘可以采用各种编码,如utf-8,保证存放于硬盘或者基于网络传输的数据量很小,提高传输效率与稳定性。

2、当前字符编码的形势

基于目前的现状,内存中的编码固定就是unicode,我们唯一可变的就是硬盘的上对应的字符编码。
此时你可能会觉得,那如果我们以后开发软时统一都用unicode编码,那么不就都统一了吗,关于统一这一点你的思路是没错的,但我们不可会使用unicode编码来编写程序的文件,因为在通篇都是英文的情况下,耗费的空间几乎会多出一倍,这样在软件读入内存或写入磁盘时,都会徒增IO次数,从而降低程序的执行效率。因而我们以后在编写程序的文件时应该统一使用一个更为精准的字符编码utf-8(用1Bytes存英文,3Bytes存中文),再次强调,内存中的编码固定使用unicode。

1、在存入磁盘时,需要将unicode转成一种更为精准的格式,utf-8:全称Unicode Transformation Format,将数据量控制到最精简

2、在读入内存时,需要将utf-8转成unicode
所以我们需要明确:内存中用unicode是为了兼容万国软件,即便是硬盘中有各国编码编写的软件,unicode也有相对应的映射关系,但在现在的开发中,程序员普遍使用utf-8编码了,估计在将来的某一天等所有老的软件都淘汰掉了情况下,就可以变成:内存utf-8<->硬盘utf-8的形式了。

八、字符编码应用之文件编辑器

1、简单介绍文件编辑器

在这里插入图片描述
这里可以选择编码格式,并不是选择的内存中的编码方式,内存固定了采用了unicode,而是指定硬盘中存储程序、数据采用什么编码格式。

2、文件存错了

在这里插入图片描述把该文件保存,,然后用notepad++重新打开:
在这里插入图片描述这个中文出现了乱码,就是存乱了。
注意:存乱了,乱码部分数据已经不可恢复。
总结:硬盘中的编码格式的选择,应该严格按照你的文件中的组成字符有哪些类型来判断选择那种编码格式存,因为utf-8支持大部分国家字符,所以现在一般都存成utf-8.

2、文件取乱了

打开一个采用GBK编码格式的文件,便只能用GBK编码格式去打开它

在这里插入图片描述

(内存)Unicode二进制字符>>>>>>编码(encode)>>>>>>(硬盘)GBK二进制字符
(硬盘)GBK二进制字符>>>>>>解码(decode)>>>>>>(内存) unicode二进制字符

你选择utf-8,那么unicode就会将Unicode二进制字符编码成utf-8。

我们把字符存的是GBK,按照shift-JIS格式解码到unicode,你觉得这些实际是GBK格式的二进制字符在shift-JIS中能找到对应的unicode二进制字符吗?

答案:肯定是不行的,所以会乱码!

总结:编码采用什么样的格式,解码就需要采用什么格式。

九、pycharm与python解释器

这里我强调下,pycharm只是一款文本编辑器,也就是说pycharm只负责python程序文件的编写,然后交给python解释器运行,python解释器再把运行结果交给pycharm显示出来。
python解释器也算是个文本编辑器,只是只能读文件,不能写文件。

#python解释器有python2和python3两个解释器:
python2:默认读文件采用ASCII码
python3:默认读文件采用utf-8

平时使用pycharm和python3解释器,因为编辑程序文件使用的是utf-8,python3解释器读文件也是采用的是utf-8,所以不会报错。
我把pycharm编码格式改成GBK:
在这里插入图片描述
为什么没有报错?再看下面这幅图:
在这里插入图片描述注:英文在那种编码格式中都不会报错,因为所有编码都支持英文字符,且都和ASCII码保持一致,都是8位表示英文。唯一一个unicode使用16位编码英文,但它是万国码兼容任何编码,所以也不会出错。但是中文在utf-8中使用24位(3个字节)表示的,所以GBK和utf-8对中文的编码不一样,所以会报错。

提出问题:
(1)我编写一个程序,之后直接运行,不保存,运行在内存中,并还没有存入硬盘,在内存中是使用unicode编码,unicode和utf-8可以转化,为什么还会出错呢?

答:普通纯粹的文件编辑器如notepad++这样确实需要保存,才会写入到硬盘,但是pycharm中只要你开始写程序,它就会先进入内存,变成unicode,再转换成GBK二进制字符持久化保存至硬盘,也就是说开始写程序时,默认就会保存到硬盘,运行时还是从硬盘加载到内存中的。因为这个时候就是python3解释器这个编辑器打开的文件,所以就要按照python3解释器的utf-8来解码硬盘中的程序和数据。

(2)我们现在都知道了python解释器都有自己默认的读取文件采用的解码格式,当我们文件的编码格式和python解释器的不一样怎么办呢?

在程序文件首行声明解码该文件所采用的编码格式:

# coding:GBK

这样就可以了。python时解释型语言,解释一行,执行一行,解释第一行,英文无论哪种编码是都可以解码出来的,第一行就告诉解释器后面内容应该采用哪种编码格式去解码。

十、第三个阶段乱码解决方案

我们的存取乱码是前两个阶段的乱码,解决方案已经讲了。第三个阶段是与字符串有关。这个很复杂,我并没有学懂,记住结论就行了。

1、python3中的字符串编码格式统一采用unicode(万国码)编码,这种编码不会存在任何乱码的可能。
2、python2中字符串的编码格式是和程序文件首行声明的编码格式是一致的,若没有声明则是和文本编辑器的编码格式一致。
3、python2这种方法有可能造成乱码。

结论:

1、现在编程如果不是公司规定采用python2,都应该尽量采用python3编程
2、如果非要用python2,应该采用下面方法避免字符串乱码:
                (1)如果字符串全是英文,不会乱码
				(2)如果有其他字符,则解决方案为:str = u'吴晋丞',u代表强制解释器采用unicode编码格式将字符串存入硬盘

猜你喜欢

转载自blog.csdn.net/weixin_44571270/article/details/105871413