编码问题

2. Python2.x中的编码

 str和unicode

str和unicode都是basestring的子类。严格意义上说,str其实是字节串,它是unicode经过编码后的字节组成的序列。对UTF-8编码的str'汉'使用len()函数时,结果是3,因为实际上,UTF-8编码的'汉' == '\xE6\xB1\x89'。

换言之,unicode是一个字符串,str是unicode这个字符串经过编码(utf8,gbk等)后的字节组成的序列。如上面utf8编码的字符串'汉'。

unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得,并且len(u'汉') == 1。

所以,在Py2里,str=bytes,。所以在2里我们可以将字节与字符串拼接。

再来看看encode()和decode()两个basestring的实例方法,理解了str和unicode的区别后,这两个方法就不会再混淆了:

#coding:utf8

u = u'苑'
print repr(u) # u'\u82d1'
# print str(u) #UnicodeEncodeError

s = u.encode('utf8')
print repr(s) #'\xe8\x8b\x91'
print str(s) # 苑
u2 = s.decode('utf8')
print repr(u2) # u'\u82d1'

2.2. 字符编码声明给谁看?

比如源代码文件hello.py中,如果有用到非ASCII字符,则需要在文件头部进行字符编码的声明,如下: 

1
#-*- coding: UTF-8 -*-

声明这句话就是告诉python2.7解释器 (默认ACSII编码方式)hello.py文件声明下面的内容按utf8编码,对,就是编码(编码成字节串最后转成0101的形式让机器去执行) 

大家注意hello.py文件保存时有自己特定的编码方式,比如utf8,比如gbk。

需要注意的是声明的编码必须与文件实际保存时用的编码一致,否则很大几率会出现代码解析异常。现在的IDE一般会自动处理这种情况,改变声明后同时换成声明的编码保存,但文本编辑器控们需要小心。所以,保存的编码样式取决于你的编辑器默认的样式(可调)。

2.3 win终端乱码原因是什么?

ok,我们现在在pycharm🔥notepad++编辑器上写了一段代码,文件名为index.py:

1
2
3
#coding:utf8<br>
ret=1+1
print '苑昊'

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

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

如何验证呢?

3. Python3.x中的编码

python3 renamed the unicode type to str ,the old str type has been replaced by bytes.

跟 Python 2 类似,Python 3 也有两种类型,一个是 Unicode,一个是 byte 码。但是他们有不同的命名。

现在你从普通文本转换成 “str” 类型后存储的是一个 unicode, “bytes” 类型存储的是 byte 串。你也可以通过一个 b 前缀来制造 byte 串。

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

Python 3 中对 Unicode 支持的最大变化就是将会没有对 byte 字节串的自动解码。如果你想要用一个 byte 字节串和一个 unicode 相链接的话,你将会得到一个错误,不管你包含的内容是什么。

所有这些在 Python 2 中都将会有隐式的处理,而在 Python 3 中你将会得到一个错误。

1
2
print('alvin'+u'yuan')#字节串和unicode连接 py2:alvinyuan
print(b'alvin'+'yuan')#字节串和unicode连接 py3:报错

咱们举个例子来看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import json
 
s='苑昊'
print(json.dumps(s))   #"\u82d1\u660a"
b1=s.encode('utf8')
 
print(b1,type(b1))     #b'\xe8\x8b\x91\xe6\x98\x8a' <class 'bytes'>
 
print(b1.decode('utf8'))#苑昊
# print(b1.decode('gbk'))# 鑻戞槉
 
b2=s.encode('gbk')
print(b2,type(b2))  #'\xd4\xb7\xea\xbb' <class 'bytes'>
print(b2.decode('gbk')) #苑昊

str() 

复制代码
# class str(object=b'', encoding='utf-8', errors='strict')
# Return a string version of object. If object is not provided, returns the empty string. Otherwise, the behavior of str() depends on
# whether encoding or errors is given, as follows.
#
# If neither encoding nor errors is given, str(object) returns object.__str__(), which is the “informal” or nicely printable string
# representation of object. For string objects, this is the string itself. If object does not have a __str__() method, then str() falls
# back to returning repr(object).
#
# If at least one of encoding or errors is given, object should be a bytes-like object (e.g. bytes or bytearray). In this case, if object
# is a bytes (or bytearray) object, then str(bytes, encoding, errors) is equivalent to bytes.decode(encoding, errors). Otherwise, the bytes
# object underlying the buffer object is obtained before calling bytes.decode(). See Binary Sequence Types — bytes, bytearray, memoryview
# and Buffer Protocol for information on buffer objects.
#
# Passing a bytes object to str() without the encoding or errors arguments falls under the first case of returning the informal string
# representation (see also the -b command-line option to Python). For example:
1
2
>>> str(b'Zoot!')
"b'Zoot!'"<br><br>
a=bytes('苑昊','utf8')
print(a) #b'\xe8\x8b\x91\xe6\x98\x8a'
print(str(a)) #b'\xe8\x8b\x91\xe6\x98\x8a'
print(str(a,'utf8'))#苑昊

  

复制代码

 

 

 

参考: http://www.ituring.com.cn/article/61192

 

posted @ 2018-01-14 11:42  skyflask  阅读(162)  评论(0编辑  收藏  举报