python2与python3的编码问题

Posted zhengaiao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python2与python3的编码问题相关的知识,希望对你有一定的参考价值。

python2与python3的编码问题

无论是python2还是python3都可以理解成是Unicode编码;

但是在电脑硬盘上存储是按照不同的映射关系的。

首先了解下:

python的encode和decode 首先明白一件事情,之前说过Unicode将所有的字符都对应上了相应的码点,而UTF-8或者ASCII码不过是对应从Unicode到字节的映射方式,既然有映射方式,那么就有映射方向。我们把从Unicode到字节码(byte string)称之为encode,把从字节码(byte string)到Unicode码称之为decode

 

一、python2注意事项

python2中,有两种不同的字符串数据类型,

一种是 “str”对象,字节存储,

另一种:如果在字符串前使用一个’u’的前缀,表示的是这个字符的Unicode码点:

 

1. Python2 处理英文字符

>>> str=‘hello‘            #首先’hello‘字符串的每个英文字符变换成unicode编码;在存储时python2对英文按照ascii射的方式编码存储5个字节编码
>>> str              
‘hello‘
>>> type(str)               #此时赋值给str,就是第一种: “str”对象,存储着字节
<type ‘str‘>
?
>>> len(str)                #len字符数,就是一字节一英文字符
5
>>> str.decode(‘ascii‘)     #‘ascii‘解码:按照ascii规则吧str英文字符由字节编码映射成字符编码,也就是把str对象类型变为unicode字符码
u‘hello‘
>>> str.decode(‘uTf-8‘)     #‘utf-8‘解码:按照utf-8规则吧str英文字符由字节编码映射成字符编码,也就是把str对象类型变为unicode字符码
u‘hello‘
                          #结果为什么结果一样,因为对待英文字符AscII和utf-8都是按照一个字节存储的, 没有什么差别
>>> print(u‘hello‘)        #关于print 函数,无论字符unicode编码还是字节ascii编码都能正常输出
hello
>>> print(str)
hello
>>>

 

2. Python2处理中文字符

  • 直接输入

>>> str="中国"          #中文在python2中是按照gbk编码的; 
>>> type(str)
<type ‘str‘>
>>> str                 #str仍然是一个str对象(字节存储)
‘xd6xd0xb9xfa‘
>>> len(str)             #len函数处理str对象,是统计str字节的个数;因为str是字节编码的
4
?
?
‘‘‘以下是对str对象的解码操作;不难发现中文在python2中是按照gbk编码的‘‘‘
?
?
>>> str.decode(‘ascii‘)    #‘ascii‘解码报错
?
Traceback (most recent call last):
 File "<pyshell#16>", line 1, in <module>
   str.decode(‘ascii‘)
UnicodeDecodeError: ‘ascii‘ codec can‘t decode byte 0xd6 in position 0: ordinal not in range(128)
>>> str.decode(‘utf-8‘)   #‘utf-8‘解码报错
?
Traceback (most recent call last):
 File "<pyshell#17>", line 1, in <module>
   str.decode(‘utf-8‘)
 File "C:Python27libencodingsutf_8.py", line 16, in decode
   return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: ‘utf8‘ codec can‘t decode byte 0xd6 in position 0: invalid continuation byte
>>> str.decode(‘gbk‘)       #‘gbk‘解码成功
u‘u4e2du56fd‘
?
?
>>> str1= str.decode(‘gbk‘)    #str(gbk)字节编码 解码为 unicode字符编码 存到str1
>>> str1.encode(‘ascii‘)       #str1 (unicode字符编码) 按照‘ascii‘编码   出错
#显然:ascii编码并不能处理unicode编码的中文,所以出错
?
Traceback (most recent call last):
 File "<pyshell#25>", line 1, in <module>
   str1.encode(‘ascii‘)
UnicodeEncodeError: ‘ascii‘ codec can‘t encode characters in position 0-1: ordinal not in range(128)
   
‘‘‘对于unicode编码的中文在python2中是按可以用‘gbk‘,‘utf-8‘编码的,但是不能被‘ascii‘编码 ‘‘‘
?
?
>>> str1.encode(‘gbk‘)  #‘gbk‘编码
‘xd6xd0xb9xfa‘
>>> str1.encode(‘utf-8‘)   #‘utf-8‘编码
‘xe4xb8xadxe5x9bxbd‘
?
?
‘‘‘print输出语句:再次证明:无论是unicode还是utf-8,gbk的字节编码都可以很好的输出‘‘‘
?
>>> print(u‘u4e2du56fd‘)
中国
>>> print(‘xd6xd0xb9xfa‘)
中国
>>> print(‘xe4xb8xadxe5x9bxbd‘)
中国
>>> str3=str1.encode(‘utf-8‘)   #又一次证明:len函数对于字节编码,按照字节算个数
>>> len(str3)
6
  • u‘字符串输入‘

>>> str=u‘中国‘ 
>>> str
u‘u4e2du56fd‘
>>> type(str)
<type ‘unicode‘>
>>> len(str)         #又一次证明:len函数对于unicode编码,按照字符个数算
2

字符串前加个u,变量按照unicode存储的。两个字节一个中文/英文字符。

所以,对于python2,强烈建议在输入字符串加个u,按照unicode编码存储。

 

 

3. Python2程序开头写#coding=utf-8的作用

Python文件编译最终还是要转换成字节码,Python2程序开头写#coding=utf-8的作用其实就是把这个Python程序文件按照utf-8编码的方式映射到字节码,如果不加这个开头,程序里面的中文会按照Python默认的ascii码方式encode,这个肯定是要报错的,大家都知道,如果程序里写了中文但是没有加这个开头,那么pycharm会在一开始就报错,也是这个道理。加了这个开头之后,程序里面的字符都将会使用utf-8编码的方式被映射到字节码,也就是上一个大节里面的byte string,值得注意的是,程序中的汉字将会以utf-8的形式编码成为字节码,因此如果需要将其decode到Unicode字符,也是需要使用utf-8方式decode。

 

4. python2因为ascii对中文(unicode)编码解码错误

  1. 错误写法:

    原因:开头并没有改变Python的系统编码方式:Python2默认的编码解码方式是ascii码

#coding=utf-8         #中文赋值按照utf-8码方式encode
?
s=‘中国‘
s_decode=s.decode(‘utf-8‘)
ps=s_decode+s      #字节编码与字符编码拼接最后是 字符编码;所以s字节编码需要解码,这时按照ascii码
print ps                      #   中文不能被‘ascii‘解码编码 ,出错                                                        
?
Traceback (most recent call last):
   ps=s_decode+s
UnicodeDecodeError: ‘ascii‘ codec can‘t decode byte 0xe4 in position 0: ordinal not in range(128)

s_decode是Unicode字符,ss是字节字符(byte string),两者相加最后的结果仍然是Unicode字符

  1. 解决办法:正确写法
>>> import sys
>>> reload(sys)
<module ‘sys‘ (built-in)>
>>> sys.setdefaultencoding(‘utf-8‘)
>>> s_decode+s
u‘u4e2du56fdu4e2du56fd‘

这个代码将Python的编码默认编码方式由ascii码换成了utf-8编码,因此s_decode+s这个就不像上面一样报错了。

或则显示指明:

#coding=utf-8
s=‘中国‘
s_decode=s.decode(‘utf-8‘)
ps=s_decode+s.decode(‘utf-8‘)
print ps              
?
python test.py
中国中国
?

 

3. 补充

>>> f=open(‘test.txt‘,‘rb‘)
>>> s=f.read()
>>> s
‘xe6x88x91xe7x88xb1xe4xb8xadxe5x9bxbd ‘
>>> s.decode(‘utf-8‘)
u‘u6211u7231u4e2du56fd ‘
>>> print s.decode(‘utf-8‘)
我爱中国
>>> print s
我爱中国

显然f.read()读出来的是字节码

 

二、python3注意事项

在python3 中 Python 3 也有两种类型,一个是 str(unicode), 一个是 byte 码。但是它们有不同的命名。 type(变量)

Python 3 中对 Unicode 支持的最大变化就是没有对 byte 字符串的自动解码

如果你想要用一个 byte 字符串和一个 unicode 相连接的话,你会得到一个错误,不管包含的内容是什么。 可以简单理解为: python2 中的unicode -> python3 的str python2 中的str-> python3 的byte

1. python3处理中文

>>> s="中"
>>> type(s)
<class ‘str‘>
>>> s            
‘中‘
>>> len(s)   #s是unicode编码 字符编码
1
>>> s.encode(‘utf-8‘)
b‘xe4xb8xad‘
?
‘‘‘任何中文的unicod编码,都不能用ascii编码/解码‘‘‘
?
?
>>> s.encode(‘ascii‘)
Traceback (most recent call last):
 File "<pyshell#5>", line 1, in <module>
   s.encode(‘ascii‘)
UnicodeEncodeError: ‘ascii‘ codec can‘t encode character ‘u4e2d‘ in position 0: ordinal not in range(128)
   
   
>>> s1=s.encode(‘utf-8‘)
>>> s1
b‘xe4xb8xad‘
>>> type(s1)
<class ‘bytes‘>
>>> s1.decode(‘utf-8‘)   #只要是unicode(str对象)就可以直接输出
‘中‘
?
?
‘‘‘对于byte.decode()解码:python3不支持二进制形式解码,python2支持‘‘‘
?
#python3
>>>‘xe4xb8xad‘.decode(‘utf-8‘)
Traceback (most recent call last):
 File "<pyshell#11>", line 1, in <module>
   ‘xe4xb8xad‘.decode(‘utf-8‘)
AttributeError: ‘str‘ object has no attribute ‘decode‘
   
#python2  
>>> ‘xe4xb8xad‘.decode(‘utf-8‘)
u‘u4e2d‘
?
#就是那么神奇!!!
?
?
‘‘‘===============print()输出函数================       ‘‘‘
‘‘‘
对于byte字节
二进制形式输出:不加b:乱码;   加b 当字符串输出
  用变量存储输出: 二进制输出
对于unicode(str):
直接输出汉字/英文
‘‘‘
>>> print(‘xe4xb8xad‘)   #utf-8
ä¸
>>> print(b‘xe4xb8xad‘)
b‘xe4xb8xad‘
?
>>> print (s)         # s: unicode  

?
>>> print(s1)           # s1变量   utf-8存储
b‘xe4xb8xad‘
?
>>> s2=s.encode(‘gbk‘)
>>> s2
b‘xd6xd0‘
?
>>> print(‘xd6xd0‘)
ÖÐ
>>> print(b‘xd6xd0‘)
b‘xd6xd0‘

文件前面 加 #coding : utf-8 无用

2. python3处理英文字符

>>> s=‘dv‘
>>> s
‘dv‘
>>> len(s)
2
>>> s.encode(‘utf-8‘)
b‘dv‘
>>> s1= s.encode(‘utf-8‘)
>>> s2=s+s1
Traceback (most recent call last):
 File "<pyshell#5>", line 1, in <module>
   s2=s+s1
TypeError: can only concatenate str (not "bytes") to str
>>> s3=s+s1.decode(‘utf-8‘)
>>> s3
‘dvdv‘

3. 输出print()函数

print (s1+s2)

s1与s2必须是str(unicode)型。不然连接报错,如上;

三、编码原由

ASCII编码 最早出现的是ASCII码,使用8位二进制数组合表示128种字符。因为ASCII编码是美国人发明的,当初没考虑给别的国家用,所以,它仅仅表示了所有美式英语的语言字符。但是没有使用完。

ISO 8859-1/windows-1252 128位字符满足了美国人的需求,但是随之欧洲人加入互联网,为了满足欧洲人的需求,8位二进制后面还有128位。这一段编码我们称之扩展字符集,即ISO 8859-1编码标准,后来欧洲的需求变更,即规定了windows-1252代替了ISO 8859-1

GB2312 然后当我国加入后,8位二进制(即一个字节)用完了,于是我们保留ASCII编码即前128位,后面的全部删除。因为我国得语言博大精深,所以需要2个字节,即16位才能满足我们得需求,所以当计算机遇到大于127的字节时,就一次性读取两个字节,将他解码成汉字。即GB2312编码

GBK 相当于GB2312的改进版,增添了中文字符。但还是2个字节表示汉字

GB18030 为了满足日韩和我国的少数民族的需求,对GBK的改进,使用变长编码,要么使用两个字节,要么使用四个字节。

Unicode 虽然每种编码都兼容ASCII编码,但是各个国家是不兼容的。于是出现了Unicode,它将所有的编码进行了统一。它不能算是一种具体的编码标准,只是将全世界的字符进行了编号,并没有指定他们具体在计算机种以什么样的形式存储。 它的具体实现有UTF-8,UTF-16,UTF-32等。

 

以上是关于python2与python3的编码问题的主要内容,如果未能解决你的问题,请参考以下文章

Python2与Python3的区别

python2.x 与 python3.x的区别

Python2 与 Python3 的编码对比

python2与python3 字符问题以及 字符编码 内容总结

python2 与 python3 的编码

python2与python3中编码与解码的区别