深入理解python字符编码

整理python在文件读取时报错和cpu执行时字符串报错UnicodeEncodeError、UnicodeDecodeError

解释py2和py3字符串数据类型,和bytes和unicode在py2和py3中的不同表现形式。

1.编码和解码

2.Python 2中的字符编码

3.Python 3中的字符编码

4.文件从磁盘到内存的编码

5.常见编码问题

 

 

1.编码和解码

字符

字符一个信息单位,它是各种文字和符号的统称,比如一个英文字母是一个字符,一个汉字是一个字符,一个标点符号也是一个字符。

字节

字节(Byte)是计算机中存储数据的单元,一个字节等于一个8位的比特,计算机中的所有数据,不论是磁盘文件上的还是网络上传输的数据(文字、图片、视频、音频文件)都是由字节组成的。

字符编码

字符编码(Character Encoding)是将字符集中的字符码映射为字节流的一种具体实现方案,常见的字符编码有 ASCII 编码、UTF-8 编码、GBK 编码等

编码、解码

编码的过程是将字符转换成字节流,解码的过程是将字节流解析为字符。

 

2.Python 2中的字符编码


python 2 中字符串类型有两种,unicode型和str型,他们存的分别是unicode数据类型和字节数据类型。str 类型的字符串的编码格式可以是 ascii、utf-8、gbk等任何一种类型。

python 2字符串数据类型

无论是utf8还是gbk都只是一种编码规则,一种把unicode数据编码成字节数据的规则,所以utf8编码的字节一定要用utf8的规则解码,否则就会出现乱码或者报错的情况。

在字符编码转换操作时,遇到最多的问题就是 UnicodeEncodeError 和 UnicodeDecodeError 错误了,这些错误的根本原因在于 Python2 默认是使用 ascii 编码进行 decode 或者 encode 操作的。

 

str 类型与 unicode 类型的字符串混合使用时,str 类型的字符串会隐式地将 str 转换成 unicode字符串,如果 str字符串是中文字符,那么就会出现UnicodeDecodeError 错误,因为 python2 默认会使用 ascii 编码来进行 decode 操作。

 

#coding:utf8

print '苑昊' #  苑昊   
print repr('苑昊')#'\xe8\x8b\x91\xe6\x98\x8a'
print (u"hello"+"yuan")  #默认使用ascii编码方式将"yuan"正确转换成unicode类型,进行字符串拼接。
#print (u'邹周'+'最帅') # UnicodeDecodeError解码错误,py2将str转换成unicode失败
#UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6
print (u'邹周'+'最帅'.decode("gbk"))   #指定解码格式,字符串拼接完成            

 

 

3.Python 3中的字符编码

 py3也有两种数据类型:str和bytes;  str类型存unicode数据,bytse类型存bytes数据,与py2比只是换了一下名字而已。

Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分,不再会对bytes字节串进行自动解码。文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示。Python 3不会以任意隐式的方式混用str和bytes,正是这使得两者的区分特别清晰。你不能拼接字符串和字节包,也无法在字节包里搜索字符串(反之亦然),也不能将字符串传入参数为字节包的函数(反之亦然)。

#print('alvin'+u'yuan')#字节串和unicode连接 py2:alvinyuan

print(b'alvin'+'yuan')#字节串和unicode连接 py3:报错 can't concat bytes to str
注意:无论py2,还是py3,与明文直接对应的就是unicode数据,打印unicode数据就会显示相应的明文(包括英文和中文)
 
 

4.文件从磁盘到内存的编码

注意:我们上面讲的string编码是在cpu执行程序时的存储状态,是另外一个过程。

还原一个py文件从创建到执行的编码过程:

文件执行前:

当我们保存hello.py的时候,hello.py文件就以pycharm默认的编码方式保存到了磁盘;关闭文件后再打开,pycharm就再以默认的编码方式对该文件打开后读到的内容进行解码,转成unicode到内存我们就看到了我们的明文。

文件执行中:

点击运行按钮或者在命令行运行该文件时,py解释器这个软件就会被调用,打开文件,然后解码存在磁盘上的bytes数据成unicode数据,这个过程和编辑器是一样的,不同的是解释器会再将这些unicode数据翻译成C代码再转成二进制的数据流,最后通过控制操作系统调用cpu来执行这些二进制数据,整个过程才算结束。

 

 

5.常见编码问题

1 cmd下的乱码问题

hello.py

1
2
#coding:utf8
print ('苑昊')

文件保存时的编码也为utf8。

思考:为什么在IDE下用2或3执行都没问题,在cmd.exe下3正确,2乱码呢?

      我们在win下的终端即cmd.exe去执行,大家注意,cmd.exe本身也一个软件;当我们python2 hello.py时,python2解释器(默认ASCII编码)去按声明的utf8编码文件,而文件又是utf8保存的,所以没问题;问题出在当我们print'苑昊'时,解释器这边正常执行,也不会报错,只是print的内容会传递给cmd.exe用来显示,而在py2里这个内容就是utf8编码的字节数据,可这个软件默认的编码解码方式是GBK,所以cmd.exe用GBK的解码方式去解码utf8自然会乱码。

py3正确的原因是传递给cmd的是unicode数据,cmd.exe可以识别内容,所以显示没问题。

明白原理了,修改就有很多方式,比如:

1
print (u'苑昊')

改成这样后,cmd下用2也不会有问题了。

2 open()中的编码问题

创建一个hello文本,保存成utf8:

苑昊,你最帅!

同目录下创建一个index.py

f=open('hello')
print(f.read())

为什么 在linux下,结果正常:苑昊,在win下,乱码:鑻戞槉(py3解释器)?

因为你的win的操作系统安装时是默认的gbk编码,而linux操作系统默认的是utf8编码;

当执行open函数时,调用的是操作系统打开文件,操作系统用默认的gbk编码去解码utf8的文件,自然乱码。

解决办法:

f=open('hello',encoding='utf8')
print(f.read())

如果你的文件保存的是gbk编码,在win 下就不用指定encoding了。

另外,如果你的win上不需要指定给操作系统encoding='utf8',那就是你安装时就是默认的utf8编码或者已经通过命令修改成了utf8编码

 

posted @ 2017-04-02 09:50  pirate邹霉  阅读(268)  评论(0编辑  收藏  举报