python字符編碼問題彙總(str、byte轉換,亂碼處理,ASCII、Unicode、UTF-8)

python字符串處理,專欄總目錄

1.python字符串格式化

2.python字符編碼

3.python字符串常用函數

 

Python 3的字符串使用Unicode,直接支持多語言。

1、ASCII、Unicode、UTF-8

ASCII編碼和Unicode編碼的區別:ASCII編碼是1個字節,擴展ASCII碼是從128-255的字符。而Unicode只是一個符號集,通常是2個字節。

本着節約的精神,又出現了把Unicode編碼轉化爲“可變長編碼”的UTF-8編碼。UTF-8編碼把一個Unicode字符根據不同的數字大小編碼成1-6個字節,常用的英文字母被編碼成1個字節,漢字通常是3個字節,只有很生僻的字符纔會被編碼成4-6個字節。

在計算機內存中,統一使用Unicode編碼,當需要保存到硬盤或者需要傳輸的時候,就轉換爲UTF-8編碼。

用記事本編輯的時候,從文件讀取的UTF-8字符被轉換爲Unicode字符到內存裏,編輯完成後,保存的時候再把Unicode轉換爲UTF-8保存到文件:

2、獲取/改變系統編碼

設置系統默認編碼爲utf-8:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

獲取系統默認編碼:

import sys
print(sys.getdefaultencoding())

3、python的字符轉換

在最新的Python 3版本中,字符串是以Unicode編碼的,也就是說,Python的字符串支持多語言,例如:

>>> print('包含中文的str')
包含中文的str

對於單個字符的編碼,Python提供了ord()函數獲取字符的整數表示chr()函數把編碼轉換爲對應的字符

>>> ord('A')
65
>>> ord('中')
20013
>>> chr(66)
'B'
>>> chr(25991)
'文'

如果知道字符的整數編碼,還可以用十六進制這麼寫str:

>>> '\u4e2d\u6587'
'中文'

兩種寫法完全是等價的。0xu4e2d=20013,0x6587=25991。

4、python字符保存

由於Python的字符串類型是str,在內存中以Unicode表示,一個字符對應若干個字節。如果要在網絡上傳輸,或者保存到磁盤上,就需要把str變爲以字節爲單位的bytes。

4.1、字符串編碼

Python對bytes類型的數據用帶b前綴的單引號或雙引號表示:

x = b'ABC'

要注意區分'ABC'和b'ABC',前者是str,後者雖然內容顯示得和前者一樣,但bytes的每個字符都只佔用一個字節。

以unicode表示的str通過encode()方法可以編碼爲指定的bytes,例如:

>>> 'ABC'.encode('ascii')
b'ABC'
>>> '中文'.encode('utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
>>> '中文'.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

1)純英文的str可以用ASCII編碼爲bytes,內容是一樣的;

2)含有中文的str可以用UTF-8編碼爲bytes;

3)含有中文的str無法用ASCII編碼,因爲中文編碼的範圍超過了ASCII編碼的範圍,Python會報錯。

在bytes中,無法顯示爲ASCII字符的字節,用\x##顯示。

4.2、字符串解碼

反過來,如果我們從網絡或磁盤上讀取了字節流,那麼讀到的數據就是bytes。要把bytes變爲str,就需要用decode()方法:

>>> b'ABC'.decode('ascii')
'ABC'
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
'中文'

如果bytes中包含無法解碼的字節,decode()方法會報錯:

>>> b'\xe4\xb8\xad\xff'.decode('utf-8')
Traceback (most recent call last):
  ...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 3: invalid start byte

如果bytes中只有一小部分無效的字節,可以傳入errors='ignore'忽略錯誤的字節:

>>> b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
'中'

5、字符窗的len()計算

要計算str包含多少個字符,可以用len()函數:

>>> len('ABC')
3
>>> len('中文')
2

len()函數計算的是str的字符數,如果換成bytes,len()函數就計算字節數:

>>> len(b'ABC')
3
>>> len(b'\xe4\xb8\xad\xe6\x96\x87')
6
>>> len('中文'.encode('utf-8'))
6

1箇中文字符經過UTF-8編碼後通常會佔用3個字節,而1個英文字符只佔用1個字節;

在操作字符串時,我們經常遇到str和bytes的互相轉換。爲了避免亂碼問題,應當始終堅持使用UTF-8編碼對str和bytes進行轉換。

文本編輯器正在使用UTF-8 without BOM編碼;

6、其它編碼轉換

當str和bytes互相轉換時,需要指定編碼。最常用的編碼是UTF-8。Python當然也支持其他編碼方式,比如把Unicode編碼成GB2312:

>>> '中文'.encode('gb2312')
b'\xd6\xd0\xce\xc4'

7、str與bytes轉換

7.1、字符表達

# bytes object
b = b"example"
# str object
s = "example"

7.2、字符格式轉換

# str轉bytes
bytes(s, encoding = "utf8")
# bytes轉str
str(b, encoding = "utf-8")

7.3、字符編解碼

  # str to bytes
  str.encode(s)
  # bytes to str
  bytes.decode(b)

8、解決python亂碼問題

字符串在python內部中是採用unicode的編碼方式,所以其他語言先decode轉換成unicode編碼,再encode轉換成utf8編碼。編碼是一種用二進制數據表示抽象字符的方式,utf8是一種編碼方式。

代碼中的字符串編碼默認和代碼文件編碼相同。

python2中的unicode和python3中的str等價。可以查看s.__class__,如果爲則爲unicode編碼及文本數據,如果爲則爲utf8編碼及二進制數據。str(s, 'utf8')和s.decode('utf8')等價。

如果字符串在代碼中被定義爲s=u'中文',則s就是python內部編碼unicode。

unicode類型再解碼會報錯。

判斷一個字符串是否爲unicode方法isinstance(s, unicode),python2中的unicode和python3中的str等價,所以在python3中判斷一個字符串是否爲unicode方法爲isinstance(s, str)。

有些IDE輸出亂碼是因爲控制檯不能輸出字符串的編碼不是程序本身的問題。比如windows的控制檯是gb2312,則utf8的輸出格式不能正確輸出。

一種輸出格式爲gb2312避免亂碼的方式:

#coding=utf-8
s='中文'
if(isinstance(s, str)):
#s爲u'中文'
    s.encode('gb2312')
else:
#s爲'中文'
    s.decode('utf8').encode('gb2312')

採用標準庫codecs模塊:

codecs.open(filename, mode='r', encoding=None, errors='strict', buffering=1)

import codecs2
f = codecs.open(filename, encoding='utf-8')

使用上邊這種方式讀進來utf-8文件,會自動轉換爲unicode。但必須明確該文件類型爲utf8類型。如果是文件中有漢字,不是一個字節一個字節地讀而是整個漢字的所有字節讀進來然後轉換成unicode(猜想跟漢字的utf8編碼有關)。

下邊的代碼也是一種使用codecs的讀寫方式:

#coding=utf-8
import codecsfin = open("test.txt", 'r')

fout = open("utf8.txt", 'w')
reader = codecs.getreader('gbk')(fin)
writer = codecs.getwriter('gbk')(fout)
data = reader.read(10) # 10是最大字節數,默認值爲-1表示儘可能大。可以避免一次處理大量數據

while data:
    writer.write(data)
    data = reader.read(10)

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章