字符编码
计算机只认识数字,我们平时在使用计算机时,用的都是人类能读懂的字符(用高级语言编程的结果也无非是在文件内写了一堆字符),如何能让计算机读懂人类的字符?必须经过一个过程: 字符--------(翻译过程)------->数字 这个过程实际就是一个字符如何对应一个特定数字的标准,这个标准称之为字符编码
一、存取文件的原理(nodepad++,pycharm,word)
- a、打开编辑器就打开了启动了一个进程,是在内存中的,所以,用编辑器编写的内容也都是存放与内存中的,断电后数据丢失
- b、要想永久保存,需要点击保存按钮:编辑器把内存的数据刷到了硬盘上。
- c、在我们编写一个py文件(没有执行),跟编写其他文件没有任何区别,都只是在编写一堆字符而已。
二、编码发展
- 阶段1:现代计算机起源于美国,最早诞生也是基于英文考虑的ASCII,ASCII:用1个字节Bytes(8位二进制)代表一个字符
- 阶段2:为了满足中文和英文,中国人定制了GBK, GBK:2Bytes代表一个中文字符,1Bytes表示一个英文字符
- 阶段3:各国有各国的标准,出现冲突,unicode出现了,能够兼容万国字符。 unicode(定长):常用2个字节(16位二进制)代表一个字符,生僻字需要用4个字节
- 阶段4:对于通篇都是英文的文本来说,unicode的式无疑是多了一倍的存储空间(二进制最终都是以电或者磁的方式存储到存储介质中的)于是产生了UTF-8(可变长,全称Unicode Transformation Format)UTF-8:对英文字符只用1Bytes表示,对中文字符用3Bytes,对其他生僻字用更多的Bytes去存。
三、乱码来源
- 乱码1:存文件时就已经乱码
- 存文件时,由于文件内有各个国家的文字,我们单以shiftjis去存, 本质上其他国家的文字在shiftjis中没有找到对应关系,不能存而硬存,肯定是乱存了,即存文件阶段就已经发生乱码,而当我们用shiftjis打开文件时,日文可以正常显示,而中文则乱码了。
- 乱码2:存文件时不乱码而读文件时乱码【按照什么标准编码的,就要按照什么标准解码】
- 存文件时用utf-8编码,保证兼容万国,不会乱码,而读文件时选择了错误的解码方式,比如gbk,则在读阶段发生乱码,读阶段发生乱码是可以解决的,选对正确的解码方式就ok了,
四、特别说明
- 指定头信息#-*-coding:utf-8-*- python解释器编码就是头信息编码, 没有指定头信息,那就使用默认的python2中默认使用ascii,python3中默认使用utf-8。
- 在python2中有两种字符串类型str(编码成文件头指定的编码格式)和unicode 在python3 中也有两种字符串类型str(直接编码成unicode)和bytes python2中的str类型就是python3的bytes类型
- 特别说明print时,open时,没指定编码格式就使用终端的编码格式。
- sys.stdout.encoding,默认就是locale的编码,print会用sys.stdout.encoding去encode()成字节流,交给terminal显示。所以locale需要与terminal一致,才能正确print打印出中文。
- 浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器
- 如果服务端encode的编码格式是utf-8, 客户端内存中收到的也是utf-8编码的结果。
- *****内存中统一采用unicode,浪费空间来换取可以转换成任意编码(不乱码),硬盘可以采用各种编码,如utf-8,保证存放于硬盘或者基于网络传输的数据量很小,提高传输效率与稳定性。*****
- ***在存入磁盘时,需要将unicode转成一种更为精准的格式,utf-8****
- ***在读入内存时,需要将utf-8转成unicode****
五、python解释器执行py文件的3个阶段
- 阶段1:启动python解释器相当于启动了一个文本编辑器
- 阶段2:从硬盘读取test.py文件内容到内存。【此时,python解释器会读取test.py的头信息#-*-coding:utf-8-*-,来决定以什么编码格式读入到内存,可以用sys.getdefaultencoding()查看,如果没有指定头信息#-*-coding:utf-8-*-,那就使用python解释器默认的编码,python2中默认使用ascii,python3中默认使用utf-8。】
- 阶段3:解释执行阶段。【在该阶段,才会识别python的语法,执行文件内代码,当执行到name="tom"时,会开辟内存空间存放字符串"tom"。】
- python解释器比文本编辑器多了阶段3
细说阶段3
- 在程序执行之前,内存中都是unicode
- 程序在执行过程中,会申请内存(与程序代码所存在的内存是俩个空间)用来存放python的数据类型的值,比如x="tom",会被python解释器识别为字符串,会申请内存空间来存放字符串类型的值,至于该字符串类型的值被识别成何种编码存放,这就与python解释器有关了,而python2与python3的字符串类型又有所不同。
- 在python2中有两种字符串类型str(编码成文件头指定的编码格式)和unicode
- 在python3中也有两种字符串类型str(直接是unicode)和bytes (也就是python2中的str)
- 字节字符串和字符字符串
- (内存)unicode----->encode-------->utf-8(硬盘)
- (硬盘)utf-8----->decode-------->unicode(内存)
六、总结
- 字符按照什么标准而编码的,就要按照什么标准解码
- 在内存中写的所有字符,一视同仁,都是unicode编码,比如我们打开编辑器,输入一个“你”,我们并不能说“你”就是一个汉字,此时它仅仅只是一个符号,该符号可能很多国家都在使用,根据我们使用的输入法不同这个字的样式可能也不太一样。只有在我们往硬盘保存或者基于网络传输时,才能确定”你“到底是一个汉字,还是一个日本字,这就是unicode转换成其他编码格式的过程了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#!/usr/bin/env python # -*- coding:utf-8 -*- #将bytes转换为str name_b = b 'tom' name_s1 = name_b.decode( 'utf-8' ) name_s2 = str (name_b,encoding = 'utf-8' ) print (name_b, type (name_b)) #b'tom' <class 'bytes'> print (name_s1, type (name_s1)) #tom <class 'str'> print (name_s2, type (name_s2)) #tom <class 'str'> #将str转换为bytes gender = 'male' gender_b1 = gender.encode( 'utf-8' ) gender_b2 = bytes(gender,encoding = 'utf-8' ) print (gender, type (gender)) #male <class 'str'> print (gender_b1, type (gender_b1)) #b'male' <class 'bytes'> print (gender_b2, type (gender_b2)) #b'male' <class 'bytes'> |