python編碼問題在此終結

morra發表於2017-02-20

1 版本差異概覽

1.1 Python 2.X:

  • str(用於8位文字和二進位制資料)
  • unicode(用於寬字元文字)

在Python2中,通用的str型別填補了二進位制資料的這一角色(特指python3中的bytes型別),因為字串也只是位元組的序列(單獨的unicode型別處理寬字串)。

在Python2中,為了相容性而使用b'xxx',但是它與'xxx'是相同的,並且產生一個str,並且,bytes只是str的同義詞。在Python3中,這二者都解決了bytes型別之間的差異。Python2中的u'xxx'和 U'xxx' Unicode字串常量形式在Python3中已經取消了,而是使用'xxx'替代,因為所有的字串都是Unicode,即便它們包含所有的ASCII字元。

1.2 Python 3.X:

  • str(用於Unicode文字,包括ASCII)
  • bytes(用 於帶有絕對位元組值的二進位制資料)
  • bytearray(bytes的一種可變的形式)

bytes是一個不可改變的字元序列。
Python 3.0 bytes物件是較小整數的一個序列,其中每個整數都在0到255之間。在python3中bytes主要用於處理那些沒有針對每個任意文字格式都編碼的raw位元組資料(影象和聲音檔案,以及用來與裝置介面的打包資料,或者你想要用python的struct模組處理的C程式)。Python3的bytes型別支援幾乎str型別所做的所有相同操作:這包括字串方法、序列操作,甚至re模組模式匹配。

bytearray是bytes型別的一個變體,它是可變的並且支援原處修改。
它支援str和bytes所支援的常見的字串操作,以及和列表相同的很多原處修改操作(例如,append和extend方法, 以及向索引賦值)。

1.3檔案分類

python3中的檔案I/O一般分為兩類:文字檔案二進位制檔案
使用建議:
1.如果正在處理影象檔案,其他程式建立的、而且必須解壓的打包資料,或者一些設 備資料流,則使用bytes和二進位制模式檔案處理它更合適。如果想要更新資料而不 在記憶體中產生其副本,也可以選擇使用bytearray。

2.如果要處理的內容實質是文字的內容,例如程式輸出、H T M L、國際化文字或 CSV或XML檔案,可能要使用str和文字模式檔案。

2 型別轉換

Python 3.0下的型別轉換:
• str.encode()和bytes(S, encoding)把一個字串轉換為其raw bytes形式,並且
在此過程中根據一個str建立一個bytes。
• bytes.decode()和str(B, encoding)把raw bytes轉換為其字串形式,並且在此
過程中根據一個bytes建立一個str。

>>> S = 'eggs' 
>>> S.encode() 
b'eggs'
>>> bytes(S, encoding='ascii') 
b'eggs'

>>> B = b'spam' 
>>> B.decode() 
'spam'
>>> str(B, encoding='ascii') 
'spam'

3 平臺預設編碼

3.1 檢視系統編碼

python2系統編碼

Python 2.7.10 (default, Jul 30 2016, 19:40:32)
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import sys
>>> sys.getdefaultencoding()
'ascii'

python3系統編碼

Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 26 2016, 10:47:25)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'

3.2 修改系統編碼

如果程式執行的過程中,遇到下面的報錯資訊時,可以把Python2的系統編碼改為utf-8。

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1....
#Python2的系統編碼改為utf-8,一般放在檔案頭
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

4 chardet模組

chardet是python的一個第三方庫,常用於編碼識別。

4.1 網頁編碼判斷:

from urllib import request
import chardet

rawdata = request.urlopen('https://www.baidu.com/').read()

tmp = chardet.detect(rawdata)
print(tmp)

"""
{'encoding': 'ascii', 'confidence': 1.0}
confidence:檢測精確度
encoding:編碼形式
"""

4.2 檔案編碼判斷

import chardet

with open('text.txt', 'rb') as f:
    data = f.readline()

tmp = chardet.detect(data)
print(tmp)
"""
{'encoding': 'ascii', 'confidence': 1.0}
"""

5 原始檔字符集編碼宣告

對於在指令碼檔案中編碼的字 符串,python預設地使用UTF-8編碼,但是,它允許我們通過包含一個註釋來指明想要 的編碼,從而將預設值修改為支援任意的字符集。這個註釋必須擁有如下的形式,並且 在Python 2.6或Python 3.0中必須作為指令碼的第一行或第二行出現:

# -*- coding: latin-1 -*-

6 pickle序列化與編碼

pickle模組的Python3版本總是建立一個bytes物件

>>> import pickle
>>> pickle.dumps([1, 2, 3]) 
b'\x80\x03]q\x00(K\x01K\x02K\x03e.'

>>> pickle.dumps([1, 2, 3], protocol=0)
b'(lp0\nL1L\naL2L\naL3L\na.'

序列化於反序列化(在python2與python3中都生效):

>>> import pickle
>>> pickle.dump([1, 2, 3], open('temp', 'wb')) 
>>> pickle.load(open('temp', 'rb')) 
[1, 2, 3]

7 編碼相關的其他方法

sys/locale模組中提供了一些獲取當前環境下的預設編碼的方法。

# coding:gbk

import sys
import locale
 
def p(f):
    print '%s.%s(): %s' % (f.__module__, f.__name__, f())
 
# 返回當前系統所使用的預設字元編碼
p(sys.getdefaultencoding)
 
# 返回用於轉換Unicode檔名至系統檔名所使用的編碼
p(sys.getfilesystemencoding)
 
# 獲取預設的區域設定並返回元祖(語言, 編碼)
p(locale.getdefaultlocale)
 
# 返回使用者設定的文字資料編碼
# 文件提到this function only returns a guess
p(locale.getpreferredencoding)

相關文章