Python3编码问题(Python2请忽略)

一、python程序编辑界面和运行界面通常都是默认unicode编码字符串的,编辑界面则是ascii编码的,也就是程序语句是用ascii编码的。但最困扰编程小白的不在这里,请看二、

二、python的文本可以通过encode转化为字节流bytes,这时候困扰编程小白的问题来了。

(1)encode转化后的字节流bytes是不是字符串?

答:bytes不是字符串str。在python中,bytes是字节流bytes对象,字符串是字符串str对象。

(2)bytes不是字符串,那b'abc'怎么跟'abc'那么像?

答:这就不得不提一下坑爹的程序语言编写者们了,或者说console界面编写者们了。注意:在运行界面输出bytes时候,它是采取这样的原则的:每读一个字节就和ascii码比对一下,如果符合ascii码的可显示字符(特殊字符,字母和数字,控制字符除外),那这个字节就按照ascii码来表示,否则就按十六进制\x某某来表示。

>>> b'\x40\x41'

b'@A'

>>> b'\x00\x01'

b'\x00\x01'

这坑爹的原则不知道坑了多少迷糊的小白:怎么一会显示一个\xff,怎么一会又显示出一个a,而且看起来又是和字符串没啥区别,搞晕了。bytes对象的显示原则是这样,所以bytes对象不能包含超过0到127内ascii码范围的unicode字符串,而不能接受超过这个范围的unicode字符串。

>>> b'中'。

File "", line 1

SyntaxError: bytes can only contain ASCII literal characters.

(3)好啦,那在编辑界面怎么输入bytes?

答:直接用b'字符串'表示bytes对象,这时候相当于一个接受0到127内ascii码范围内的unicode码字符串的函数bytes(‘字符串’)。

>>> b'@&*hello'

b'@&*hello'

(4)好,如果我不用字符串表示bytes呢?又怎么搞?

答:直接用\x加两位十六进制数字表示一个字节就可以了。

>>> b'\x41\xff\x2e\97'

b'A\xff.\\97'

(5)字符串可以通过encode转化为bytes,bytes可以通过decode转化为字符串,问题又来了,不是学挖掘机哪家强,而是一个字符a有很多种编码的,按哪一种转化为bytes?bytes本身就是一串0和1的数字,按不同方式读可以解释成不同的字符,又怎么搞?

答:encode(‘编码方式’)时指定按那个编码转化为bytes。反之,decode(‘编码方式’)指定按那种方式读取字节码(0和1构成的数字流)。

>>> 'a'.encode('ascii')

b'a'

>>> 'a'.encode('utf-8')

b'a'

>>> 'a'.encode('gbk')

b'a'

>>> '中'.encode('gbk')

b'\xd6\xd0'

>>> '中'.encode('utf-8')

b'\xe4\xb8\xad'

(6)坑爹的问题又来了,python程序编辑界面的unicode码u'a'是字符串还是字节码?unicode码又怎么表示?

答:u'a'不是字节码,是字符串!坑爹啊!换句话说u'a'和'a'是一样一样的!坑爹啊!

>>> type(u'a')

<class 'str'>


unicode码再python里有两种表示方式:

u'字符串'或者'\u四位十六进制数'。它们是等价的,而且都是str对象。注意,'\\u四位十六进制数'与'\u四位十六进制数'并不相等,'\\u四位十六进制数'='\\’(斜杠本身是转义字符要经过转义表示)+'u四位十六进制数'。

>>> print('\u0065')

e

>>> print('\\u0065')

\u0065

(7)那如果它是字符串,我要转化为unicode码咋整?用encode指定unicode方式?

答:如果需要将内存用的unicode码直接保存,就指定编码方式是'unicode-escape'!

>>> '中'.encode('unicode')

Traceback (most recent call last):  File "", line 1, inLookupError: unknown encoding: unicode

>>> '中'.encode('unicode-escape')

b'\\u4e2d'

好!如果我不指定编码方式呢,又会怎么样?

encode默认编码方式是!!!utf-8!

>>> '中'.encode()

b'\xe4\xb8\xad'


三、python的py文件里指定编码方式,是指指定文件里所有内容都是按编码方式编码还是字符串按编码方式编码?

答:py文件的编码方式是ascii码,字符串默认编码是unicode码,指定编码方式是指定从硬盘读取py文件的编码方式。

实际上,要区分以下编码:系统默认编码(cmd,widows的txt文件),编辑界面编码(编辑界面显示文本的编码),运行界面编码(运行界面显示文本的编码),代码文件(py文件)编码,读入的文本编码,写出的文本编码。

(1)系统默认编码

以windows简体中文为例,系统默认编码是gbk,命令行输入chcp查看活动页代码为936。

如果将超出gbk范围的unicode码,写入系统的txt文件,报错!在cmd中print,报错!

处理方式:将unicode码encode为bytes再写入或print。

(2)编辑界面编码

编辑界面编码默认是ascii码,也就是写的程序语句默认是ascii编码,但一旦涉及到ascii码不能表示的,就隐形转换为系统默认编码表示,程序语句中的字符串默认是unicode码,也就是内存中的编码。

在py文件头声明文件的编码方式:

#-*- coding:utf-8 -*-

对编辑界面的字符串没有什么实质上的影响的!

pycharm编辑界面是默认utf-8的。所以有时在pycharm中编辑的代码中没有问题的字符串,放到cmd中编辑就会出现问题。设置在Editor->Code Style->File Ecoding->Project Ecoding。

(3)运行界面编码

cmd中运行程序,默认显示文本的编码是ascii码,一旦超出范围就隐式转换为系统编码。

在py文件头声明文件的编码方式:

#-*- coding:utf-8 -*-

对编辑界面和运行界面的字符串也没有什么实质上的影响的!坑爹啊!指定编码方式是告诉系统按照什么编码来读这个py文件的。

pycharm运行界面是默认utf-8的。所以有时在pycharm中没有问题的字符串,放到cmd中就会出现问题。所以有时在pycharm中print没有问题的字符串,放到cmd中print就会出现问题。设置在Editor->Code Style->File Ecoding->IDE Ecoding。

(4)代码文件编码

代码文件(py文件)本身也是一个文本,它也需要在硬盘或者其他载体上保存,默认编码是系统编码。这样的话,一旦py文件copy到不同平台,问题就会发生,出现乱码。

特别注意:

在py文件头声明文件的编码方式:

#-*- coding:utf-8 -*-

只是告诉python编译器在读取代码文件时按utf-8方式读取,但这个声明不能将py文件保存成utf-8格式的!

处理方式:

py文件要多平台运行,最好统一采用一个编码方式(如‘utf-8’)编辑和保存。

(5)读入文件编码

当从网络或者硬盘读入文件的时候,实质上读到的是字节流:

硬盘读入文件的默认编码方式是系统编码方式,当出现超过gbk范围的字节出现,报错!

网络读入文件时,因为读入的是字节,不会报错,但一旦要print时就会报错!

所以,如果不能按照读入文本的编码方式转化为unicode,就会出现问题。

处理方式:

因为read()没有编码方式参数,只能读入bytes然后在解码为unicode码或者其他编码。

判断读入内容的编码方式可以用chardet的detect方法,接受一段bytes参数,返回一个结果的字典,里面包含编码方式和信度区间。

withopen('/Users/liaorikun/Desktop/gbktest.txt','rb')asf:

s = f.read()

chatest = chardet.detect(s)

# print(s)

print(chatest)

检测结果:

{'encoding': 'GB2312', 'confidence': 0.99}

(6)写出文件编码

写文件编码参看(1)

如果想将文本直接以unicode码保存到文件,用encode(‘unicode-escape’)转化为bytes,写入文件。

如果想将文本以utf-8形式保存到文件,用encode(‘utf-8’)转化为utf-8编码的bytes,写入文件。

推荐阅读更多精彩内容