人类可以理解、易懂的信息称为“明文”(plain text
)。为了传递信息,我们需要能将明文记录的信息,转成另外某种标准记录的信息进行传递,同时为了接收信息,我们还需要能将另外某种标准记录的信息,转回成明文记录的信息。比如打电话,需要将语音信息,转换成模拟信号或者数字信号记录的信息进行传递;同时,还需要将模拟信号或者数字信号记录的信息,转换成语音信息。
将明文转成另外某种标准记录的信息的方式称为“编码”,从另外某种标准记录的信息转回成明文的方式则为“解码”。
文件在保存时,存储在磁盘中的格式为通过某种编码格式规范方式编码的字节码bytes
。文件在保存之前,数据是存在于内存中,在内存中存储的格式是unicode
。
当一个软件保存文件时,首先读取内存中unicode
的数据,然后将内存中unicode
的数据,按照软件默认指定的编码格式规范,例如utf8
,转换成字节码bytes
,保存在磁盘上。
当一个软件打开文件时,首先读取磁盘上字节码bytes
的数据,然后按照软件默认指定的解码格式规范,比如utf8
,将字节码bytes
解码成unicode
存储在内存中,从而显示在屏幕上。
如果文件保存时,使用的是utf8
格式规范进行编码,那么如果打开文件时,使用的也是utf8
格式规范进行解码,文件就能正常解码;如果打开文件时,使用的不是utf8
格式规范进行解码,比如BGK
格式规范进行,因为编码时格式规范与解码时的格式规范不同,所以不能正常解码,显示为乱码。
比如Windown
系统默认使用的GBK
格式规范,所以编码和解码时,使用的也是GBK
格式规范。而Linux
或Unix
系统默认使用的是utf8
格式规范,编码和解码时,使用的也是utf8
格式规范。所以,如果在Windown系统下保存的文件,使用的是默认的GBK
格式规范编码,那么在Linux
或Unix
系统下打开时,使用的是默认的utf8
格式规范解码,编码与解码的格式规范不同,不能正常解码,显示为乱码。
ascii
编码是采用1个字节
来存储,也就是8位
,最多只能表示2^8
也即256
个字符。这在全世界各种语言文字上远远不够,单拿中国汉字来讲,常用的汉字也有6000
多个。因此,为了满足全球各个国家不同语言的编码需求,全球统一码联盟提出了unicode
编码。unicode
编码默认情况下会采用2个字节
存储字符(UCS-2),这样能够存储的2^16
也即65536
个字符,但也还是不能满足全世界所有语言,因此后来又补充了用4个字节
存储(UCS-4),这就可以包含全球所有的文字了。
unicode
是一个字符集,相当于一个字典,全世界所有的字符或者标点符号都对应一个数字。计算机中显示这个字符的时候,就使用unicode
字符集中对应的那个数字就可以了。
utf-8
、gbk
、latin-1
、ascii
都是具体的编码实现。 因为unicode
中,将大部分的字符都用2个字节存储,但是对于英文字母,比如a
,其实他只需要一个字节就够了,如果都用2个字节存储,那么比较浪费硬盘空间或者浪费流量,因此unicode
并不适合用来存储。而utf-8
则是unicode
的一种实现方式,他默认会使用8
位,也就是一个字节存储,如果存储不下了,则会动态的改变大小用来存储字符。因此utf-8
比较节省空间,并且也可以包含全世界所有的字符。
因为Python
早于unicode
发布,在Python2
版本中,默认的字符串编码采用的是ascii
格式规范。Python2
在读取文本文件时,默认会将文本中byte
按ascii
格式规范解码为unicode
,一旦遇到非ASCII
字符,解码就会失败,出现UnicodeDecodeError
的错误。
在文件开头位置声明#coding:utf8
,用来告诉Python
解释器在读取这个源代码文件时,不要使用默认的ascii
格式规范解码,而是用utf8
来解码。而python3
的解释器默认使用utf8
编码,所以不需求声明。所以python
文件必须保存为utf8
格式。
import sys
# 显示python默认的编码格式
print(sys.getdefaultencoding())
# ascii
reload(sys)
# 设置字符串在转换编码时候的默认编码
sys.setdefaultencoding(‘utf-8‘)
print(sys.getdefaultencoding())
# utf-8
python2
中,有两种字符串类型:str
类型和unicode
类型。str
类型是字节数据,unicode
类型是unicode
数据。unicode
类型是明文,将unicode
类型转换为str
类型,就是编码encode
,将str
类型转换为unicode
类型,就是解码decode
。
#coding:utf8
s1=‘张‘ # 字节码
print type(s1)
# <type ‘str‘>
# 内置函数repr返回一个对象的string格式
print repr(s1)
# ‘\xe5\xbc\xa0‘
s2=u‘三‘
print type(s2)
# <type ‘unicode‘>
print repr(s2)
# u‘\u4e09‘
s3=‘张三‘ #字节码
# 用utf8格式规范解码
u=s3.decode(‘utf8‘)
print u
# 张三
print type(u)
# <type ‘unicode‘>
print repr(u)
# u‘\u5f20\u4e09‘
print repr(s2)
# u‘\u4e09‘
# 用utf8格式规范编码
b=s2.encode(‘utf8‘)
print b
# 三
print type(b)
# <type ‘str‘>
print repr(b)
# ‘\xe4\xb8\x89‘
# 用gbk格式规范解码,出错
u2=s1.decode(‘gbk‘)
print len(‘张三‘)
# 6(字节码长度)
python3
也有两种数据类型:str
和bytes
。str
类型是unicode
数据,bytse
类型是bytes
数据。python3
将python2
中的unicode
数据类型重命名为str
类型,将python2
中的str
类型重命名为bytes
类型。python3
的解释器默认使用utf8
编码。
import json
s=‘张三‘ # unicode
print(type(s))
# <class ‘str‘>
print(json.dumps(s))
# "\u5f20\u4e09"
b=s.encode(‘utf8‘)
print(type(b))
# <class ‘bytes‘>
print(b)
b‘\xe5\xbc\xa0\xe4\xb8\x89‘
u=b.decode(‘utf8‘)
print(type(u))
# <class ‘str‘>
print(u)
# 张三
print(json.dumps(u))
# "\u5f20\u4e09"
print(len(s))
# 2
命令行乱码问题
cmd.exe
本身也一个软件,python2
解释器按声明的utf8
编码文件,解释器正常执行,也不会报错。但是python2
将print
的内容会传递给cmd.exe
用来显示时,python2
传递的是utf8
编码的字节数据,但cmd.exe
默认的编码解码方式是GBK
,所以用GBK
的解码方式去解码utf8
就会出现乱码。python3
传递给的是unicode
数据,cmd.exe可以识别内容,所以显示没问题。
open()中的编码问题
当执行open
函数时,调用的是操作系统打开文件,操作系统用默认的gbk
编码去解码utf8
的文件,就会出现乱码。可以使用open(‘hello‘,encoding=‘utf8‘)
,指定文件打开的编码规范。
原文:https://www.cnblogs.com/fiezwang/p/14358559.html