python2与python3的编码问题
2021-04-18 10:27
标签:and 必须 str errors invalid codec 输出 欧洲 python 无论是python2还是python3都可以理解成是Unicode编码; 但是在电脑硬盘上存储是按照不同的映射关系的。 首先了解下: python的encode和decode 首先明白一件事情,之前说过Unicode将所有的字符都对应上了相应的码点,而UTF-8或者ASCII码不过是对应从Unicode到字节的映射方式,既然有映射方式,那么就有映射方向。我们把从Unicode到字节码(byte string)称之为encode,把从字节码(byte string)到Unicode码称之为decode python2中,有两种不同的字符串数据类型, 一种是 “str”对象,字节存储, 另一种:如果在字符串前使用一个’u’的前缀,表示的是这个字符的Unicode码点: python2与python3的编码问题
一、python2注意事项
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对象(字节存储)
‘\xd6\xd0\xb9\xfa‘
>>> len(str) #len函数处理str对象,是统计str字节的个数;因为str是字节编码的
4
?
?
‘‘‘以下是对str对象的解码操作;不难发现中文在python2中是按照gbk编码的‘‘‘
?
?
>>> str.decode(‘ascii‘) #‘ascii‘解码报错
?
Traceback (most recent call last):
File "", 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 "", line 1, in module>
str.decode(‘utf-8‘)
File "C:\Python27\lib\encodings\utf_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‘\u4e2d\u56fd‘
?
?
>>> str1= str.decode(‘gbk‘) #str(gbk)字节编码 解码为 unicode字符编码 存到str1
>>> str1.encode(‘ascii‘) #str1 (unicode字符编码) 按照‘ascii‘编码 出错
#显然:ascii编码并不能处理unicode编码的中文,所以出错
?
Traceback (most recent call last):
File "", 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‘编码
‘\xd6\xd0\xb9\xfa‘
>>> str1.encode(‘utf-8‘) #‘utf-8‘编码
‘\xe4\xb8\xad\xe5\x9b\xbd‘
?
?
‘‘‘print输出语句:再次证明:无论是unicode还是utf-8,gbk的字节编码都可以很好的输出‘‘‘
?
>>> print(u‘\u4e2d\u56fd‘)
中国
>>> print(‘\xd6\xd0\xb9\xfa‘)
中国
>>> print(‘\xe4\xb8\xad\xe5\x9b\xbd‘)
中国
>>> str3=str1.encode(‘utf-8‘) #又一次证明:len函数对于字节编码,按照字节算个数
>>> len(str3)
6
-
u‘字符串输入‘
>>> str=u‘中国‘
>>> str
u‘\u4e2d\u56fd‘
>>> 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)编码解码错误
-
错误写法:
原因:开头并没有改变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字符
-
解决办法:正确写法
>>> import sys
>>> reload(sys)
module ‘sys‘ (built-in)>
>>> sys.setdefaultencoding(‘utf-8‘)
>>> s_decode+s
u‘\u4e2d\u56fd\u4e2d\u56fd‘
这个代码将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
‘\xe6\x88\x91\xe7\x88\xb1\xe4\xb8\xad\xe5\x9b\xbd\n‘
>>> s.decode(‘utf-8‘)
u‘\u6211\u7231\u4e2d\u56fd\n‘
>>> 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‘\xe4\xb8\xad‘
?
‘‘‘任何中文的unicod编码,都不能用ascii编码/解码‘‘‘
?
?
>>> s.encode(‘ascii‘)
Traceback (most recent call last):
File "", 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‘\xe4\xb8\xad‘
>>> type(s1)
class ‘bytes‘>
>>> s1.decode(‘utf-8‘) #只要是unicode(str对象)就可以直接输出
‘中‘
?
?
‘‘‘对于byte.decode()解码:python3不支持二进制形式解码,python2支持‘‘‘
?
#python3
>>>‘\xe4\xb8\xad‘.decode(‘utf-8‘)
Traceback (most recent call last):
File "", line 1, in module>
‘\xe4\xb8\xad‘.decode(‘utf-8‘)
AttributeError: ‘str‘ object has no attribute ‘decode‘
#python2
>>> ‘\xe4\xb8\xad‘.decode(‘utf-8‘)
u‘\u4e2d‘
?
#就是那么神奇!!!
?
?
‘‘‘===============print()输出函数================ ‘‘‘
‘‘‘
对于byte字节
二进制形式输出:不加b:乱码; 加b 当字符串输出
用变量存储输出: 二进制输出
对于unicode(str):
直接输出汉字/英文
‘‘‘
>>> print(‘\xe4\xb8\xad‘) #utf-8
丕
>>> print(b‘\xe4\xb8\xad‘)
b‘\xe4\xb8\xad‘
?
>>> print (s) # s: unicode
中
?
>>> print(s1) # s1变量 utf-8存储
b‘\xe4\xb8\xad‘
?
>>> s2=s.encode(‘gbk‘)
>>> s2
b‘\xd6\xd0‘
?
>>> print(‘\xd6\xd0‘)
ÖÐ
>>> print(b‘\xd6\xd0‘)
b‘\xd6\xd0‘
文件前面 加 #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 "", 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的编码问题
标签:and 必须 str errors invalid codec 输出 欧洲 python
原文地址:https://www.cnblogs.com/zhengaiao/p/13295654.html
上一篇:常见算法
下一篇:java基础09- 抽象类
文章标题:python2与python3的编码问题
文章链接:http://soscw.com/index.php/essay/76250.html