python编码问题

相关知识

1.字节(Byte):计算机中数据存储的基本单位,一个字节是8位.计算机上所有的数据都是由字节组成的

2.字符:字符是一个信息单位,是各种文字和符号的统称.(一个英文字母,一个汉字都是一个字符)

3.字符集(Characterset):是某个范围内字符的集合,不同的字符集规定了字符的个数.如:ASCII,GB2312

4.字符码:字符集中每个字符的数字编号

5.字符编码(character encoding):将字符集中的字符码映射为字节流的一种具体实现方案,如ASCII,UTF-8,GBK编码.某种意义上来说,字符集与字符编码有对应关系:ASCII字符集对应ASCII编码

编码&解码

编码的过程是将字符转化为字节流

解码的过程是将字节流解析为字符

编码类型及特点

Unicode:又被称为统一码、万国码,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

UTF-8编码:通用转换格式 ,是一种可“变长”的编码格式,即把英文变长为1个字节,而汉字用3个字节表示,特别生僻的还会变成4-6字节。所以如果是传输或存储大量英文的话,UTF编码格式优势非常明显。是最流行的一种对 Unicode 进行传播和存储的编码方式。它用不同的 bytes 来表示每一个代码点。ASCII是UTF-8的一个子集

Unicode和UTF-8的比较

比如大写字母A,用二进制表示为0100 0001,而用UNICODE的话,就必须用0来补足多出来的一个字节,即表示为00000000 01000001。UNICODE编码太浪费空间了,足足大了一倍的空间。

GB2312:GB2312是中国规定的汉字编码---简体中文的字符集编码,GBK是GB2312的扩充,兼容GB2312还能够显示繁体中文和日文的片假名。

不同编码格式和UNICODE之间的转换

为了在不同的编码格式之间进行转换,我们必须对字符进行编码和解码的工作。任何非UNICODE格式的字符(串),我们都可以使用decode方法将其解码为UNICODE编码的字符(串),这种转换过程叫“解码”。

同样道理,UNICODE格式的字符(串),也可以通过encode()方法将其编码为其他编码格式的字符(串),这个过程叫“编码”

总结一下就是:

  1. 为了处理英文字符,产生了ASCII码。 

  2. 为了处理中文字符,产生了GB2312。 

  3. 为了处理各国字符,产生了Unicode。 

  4. 为了提高Unicode存储和传输性能,产生了UTF-8,它是Unicode的一种实现形式。

decode( )和encode( )

1. decode( ):

decode() 的作用是将其他编码的字符串转换成Unicode编码

如:name.decode(“GB2312”)---表示将GB2312编码的字符串name转换成Unicode编码。

调用方式:字符串.decode("字符串的编码方式")

2. encode( ):

encode() 的作用是将Unicode编码转换成其他编码的字符串

如:name.encode("GB2312")---表示将那么转换为GB2312的字符串

调用方式:字符串.decode("字符串的编码方式")

(如果不输入形参,即默认该变量的编码方式是Unicode)

运行环境的影响

(1)所谓乱码的本质是字符的编码格式与显示字符的环境编码格式不一致引起的。这句话告诉我们要解决乱码问题,我们需要知道两个信息,一个是字符本身是什么编码,另一个就是显示字符的环境编码是什么,两者必须一致,才能显示出正确的内容。

(2)由于Unicode编码是标准编码格式,也可以看做是没有任何特定编码格式的“无编码”模式。所以,对于任何Unicode类型编码的字符,打印时python会自动根据环境编码转为特定编码后再显示。

在不同的python版本中,字符编码的方式也不一样。

比较麻烦的是py2,如果用py2来写脚本的话,因为默认py2是用ascii来编码脚本的,所以如果你的脚本中出现了中文,就必须在脚本的开始位置注明支持中文的编码格式,否则会报错。

所有支持中文的编码格式都是可以的,比如声明为#coding:utf8或#coding:gbk都是可以的。注明以后,我们就可以在脚本中随意使用中文了。

在py2中,所有字符串的编码方式默认是用ascii来进行编码的,如果通过coding:xxx的方式声明了脚本的编码方式,则字符串会按照声明的字符编码格式来进行编码,而字符串变量类型是为str类型的。

py2中str一定是有特定编码的,不是Unicode格式。而py3字符串默认是Unicode编码的,​​​​​​

如在pycharm编辑器中

原因是这里a变量的编码是gbk的,而我们运行脚本的编辑器pycharm设置的环境编码却是utf8,两者编码方式并不一致,所以必定会出现乱码。

解决方案

一种是修改#coding:gbk为#coding:utf8,

二是可以在'中国'前面加一个u,即a=u'中国'。

在前面加u是将“中国”强制转换为unicode编码,即“无编码”,此时变量的type将会变为unicode。前面已经说过,对于unicode编码的字符,python将自动根据环境编码进行显示,所以也就是会自动帮我们编码为utf8进行显示。还有一种方式是通过encode和decode函数,比如像下面

使用decode方法可以将字符串进行解码,解码后格式就是Unicode了,所以a.decode('gbk')这句跟u"中国"效果是等价的,打印出来当然是没问题的。当然,我们也可以明确写出要编码的类型,比如a.decode(‘gbk').encode(‘utf8'),这样将Unicode明确地编码为utf8,也是一样的效果。这里大家要注意一点,我们对所有非Unicode类型的字符只能进行decode操作,不能进行encode操作。对Unicode类型的只能是encode而不能decode。

在命令行中运行

果不其然,b1正常显示了,b2却出现了乱码。这次出现乱码的原因又是什么呢?

这里大家要知道,命令行里面的环境编码是gbk格式,由于b1是Unicode编码,Unicode编码的字符会自动随着环境编码来输出,所以不管在什么环境下,b1都能正常显示输出。而b2由于被encode成了utf8格式,所以它只能在环境编码为utf8的环境中才能正常显示,在命令行这种环境下就会出现由于编码不一致而导致的乱码。大家可以试试直接print a,由于文件是coding:gbk的,所以a是可以直接正常显示的。比如代码如下:

 

如果是py3的脚本的话,则要简单得多。因为py3中,所有的字符串不再受系统环境编码的影响,统一使用Unicode来进行编码,类型统一为str,所以不再需要在中文前面加u来使中文字符变为Unicode这种写法。

并且所有py3的脚本默认都是utf8来编码的,所以我们也不需要在脚本开头指定coding:xxxx了

打印显示的时候也会方便很多,由于是字符串都是Unicode格式,所以不管在命令行中还是pycharm中,都会正常显示而不会出现乱码。

要弄清楚字符本身的编码和环境编码,只要这两者一致了,那一定不会出现乱码。

在python shell(即命令行)中直接写代码运行时,大家只需注意在windows下,命令行的默认编码是gbk的,而在Linux环境下,命令行的默认编码是utf8的,其他没什么区别。

第一行我们在定义a="中国"时,并不会报错,因为在命令行中默认是gbk编码,所以此时其实a的编码已经是gbk了,支持中文没有任何问题。

print a也不会报错,因为按照gbk方式编码并且在gbk环境中运行,不可能会出问题。

下面直接将a进行decode解码时,解码方式必须跟编码方式是一致的,所以gbk方式编码的内容不能解码为utf8格式,只能decode为gbk。

decode之后,字符串会变为Unicode,也可以正常显示。

最后,我们将Unicode编码为utf8时,字符的编码格式又跟环境编码不一致了,所以再次出现了乱码。py3同理,就不再赘述了,如果掌握了之前说的原则,应该完全不会出现问题。如果是在Linux下面的命令行中运行,道理也是一样,只是需要注意linux下命令行默认的编码格式是utf8的就可以了。

参考1

参考2

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值