一、解碼問題: ‘utf-8’ codec can’t decode byte 0xa8 in position xx: invalid start byte
【問題描述】:
筆者通過Python3從數(shù)據(jù)庫(HBase)中取數(shù)據(jù)的時候,報錯如下:
報錯信息顯示,在內(nèi)置函數(shù)轉(zhuǎn)換獲取的數(shù)據(jù)(字節(jié)數(shù)組)為字符串str時,UTF-8編碼方案無法對字節(jié)\xa8 進(jìn)行解碼,該字節(jié)0xa8 在當(dāng)前字節(jié)數(shù)組的索引是21 (從0開始計數(shù))。
【問題分析】:
在解決這個問題之前,我們首先來回顧一下Python3中編碼和解碼之間的轉(zhuǎn)換關(guān)系如下(欲全面了解編碼和解碼問題詳情點擊此處):
可見,當(dāng)數(shù)據(jù)含有中文或其他特殊字符時,Unicode碼被編碼成非UTF-8和非ASCII碼(如GBK碼)后,再用UTF-8解碼就會出錯。因為,它們根本就不是一套編碼方案。
本例中,我無法解碼的數(shù)據(jù)在本地的顯示是:
Ecole Polytechnique Fédérale de Lausanne (EPFL)
在數(shù)據(jù)庫中的顯示是:
我們都知道Python中,UTF-8 碼會將Unicode 碼中的每個非ASCII字符編碼成2~3個字節(jié)(中文是3個字節(jié),這里的é 是兩個字節(jié)),格式是\x## 。
所以,我們可以推斷出,在數(shù)據(jù)被傳輸或存儲前,Unicode 碼所表示的str,被轉(zhuǎn)換成了非UTF-8 編碼。這自然在編輯或獲取數(shù)據(jù)時,無法用UTF-8 碼解碼成Unicode 碼,上例中的第一個非ASCII字節(jié)\xA8 即為報錯信息索引為21 中的0xa8 。
至此,我們完全理解了為什么會出錯,和具體在哪個位置出的錯。
【解決思路】:
- 在str數(shù)據(jù)被傳輸或存儲前,保證其為
Unicode 碼,再對其進(jìn)行UTF-8編碼(.encode('utf-8') )。
- 在str數(shù)據(jù)被編輯或獲取前,對其進(jìn)行UTF-8解碼(
.decode('utf-8') )為Unicode 碼。
- 對于需要和數(shù)據(jù)庫交互的情況,往往譬如
insert() 或get() 等方法都會內(nèi)置字符串str和字節(jié)數(shù)組bytes之間的轉(zhuǎn)換函數(shù),為防止其不被轉(zhuǎn)換成GBK等其他編碼,所以只要在傳入數(shù)據(jù)前保證其為Unicode 碼即可。
本例中我的解決方案:
保證上傳的字段value 為Unicode 碼,即成功。
def function(...,value=str(value).encode('utf-8').decode('utf-8'),...)
被utf-8 編碼后的數(shù)據(jù)在數(shù)據(jù)庫中的顯示,該字節(jié)可被utf-8 解碼為Unicode 碼:
二、編碼問題:‘gbk’ codec can’t encode character ‘\uxxxx’ in position xxxxx: illegal multibyte sequence
【問題描述】:筆者在Windows系統(tǒng)下嘗試將數(shù)據(jù)庫中數(shù)據(jù)讀取出來,并寫入到本地.txt文件中報錯。
報錯代碼如下:
with open('C:\\Users\\Administrator\\xxx\\content.txt', 'w') as f:
f.write(str_data)
讀取亦然:
with open('C:\\Users\\Administrator\\xxx\\content.txt', 'r') as f:
str_data = f.read()
意思是在索引為26088的'\u0141' Unicode碼表示的字節(jié)無法被GBK 編碼方案編碼。
【問題分析】:
Windows系統(tǒng)默認(rèn)是GBK編碼,所以在單獨設(shè)置編碼方案的時候,系統(tǒng)會自動默認(rèn)為GBK編碼,對于含有非中文的字符就無法編碼。
【解決方案】:
不論數(shù)據(jù)中是否含有中文等非ASCII字符,直接編碼成UTF-8 即可。
with open('C:\\Users\\Administrator\\xxx\\content.txt', 'w', encoding='utf-8') as f:
f.write(str_data)
|