2015-03-03 85 views
4

我有一個編碼爲utf-16的文本文件,它引發以下字符的異常:'\u0153'Python加載'utf-16'文件無法解碼' u0153'

UnicodeEncodeError: 'charmap' codec can't encode character '\u0153' in position

我用一個很簡單的腳本加載該文件,我也試過忽略錯誤,而無濟於事。我究竟做錯了什麼?

with open(filename, "r", encoding="utf-16", errors='replace') as data_file:  
    print(data_file.read()) 

這是破壞了文件的一部分:

 
["Xinhua","Ürümqi"] 

編輯: 不知道爲什麼,我的問題是誤解。希望這是更好的形成。

我應該怎樣用Python讀這個文件?

Sample file link含(UTF-16-LE文件):

 
["Xinhua","Ürümqi"] 

爲什麼沒有此代碼的工作?

with open(filename, "r", encoding="utf-16", errors='replace') as data_file:  
    print(data_file.read()) 
+0

你確定你知道哪一行失敗嗎? – 2015-03-03 02:47:47

+0

請從該文件的副本中刪除大塊文本,直到找到產生問題的最小可能文件,然後發佈最小可能文件的*十六進制轉儲*。 – zwol 2015-03-03 02:51:29

+0

編碼是大還是小?您正在閱讀的文件是否包含字節順序標記(BOM)? – Frank 2015-03-03 04:13:58

回答

5

最初難倒你,是因爲你正在運行的Python終端仿真器內的異常(或可能「控制檯窗口」是一個常用術語?)不能顯示所有以Unicode字符。爲了解決這個問題,你需要讓自己擁有一個支持Unicode的終端仿真器,然後確保Python 知道它在支持Unicode的終端仿真器中運行。如果您不知道如何操作,請在superuser.com上提出一個新問題,指定您的操作系統。

我的終端模擬器可以顯示所有的Unicode字符,假設所有必要的字體是可用的,Python知道這一點,所以我能做到這一點,並沒有得到一個異常:

>>> with open("countryCity2.json", "r", encoding="utf-16") as f: 
... x = f.read() 
... 
>>> print(x) 
["Xinhua","Ürümqi"] 

然而,那不是你唯一的問題。您的輸入文件的編碼已被破壞。 Ãœrümqi不是任何語言中有意義的字符序列。但是,它符合從傳統編碼轉換爲UTF-8的文本特徵mojibake,然後 - 錯誤地轉換爲Unicode編碼再次。 1個字節,看到如果我們得到一個合法的UTF-8字節序列:

>>> print(x.encode("iso-8859-1").decode("utf-8")) 
["Xinhua","Ürümqi"] 

Ürümqi」是一個真正的字,並會振振有詞地出現在結合「Xinhua」我們可以通過1將它進行測試。此外,如果文本不誤轉換後的UTF-8,我們會看到一個例外:

>>> "Ürümqi".encode("iso-8859-1").decode("utf-8") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xdc in position 0: 
    invalid continuation byte 

所以假設得到了證實。

在一個程序,不得不處理了大量的文件,它們的編碼可能會或可能不會被這樣缺胳膊少腿,我會做這樣的事情:我在這裏使用ISO 8859.1編碼

for fname in input_files: 
    with open(fname, "r", encoding="utf-16") as f: 
     contents = f.read() 
    try: 
     contents = contents.encode("iso-8859-1").decode("utf-8") 
    except (UnicodeEncodeError, UnicodeDecodeError): 
     pass 
    process_file(fname, contents) 

而不是,因爲文本是或曾經在編碼中,但是因爲Python的iso-8859-1編解碼器是從字符U + 0000..U + 00FF到字節0x00..0xFF的標識映射。 (在技術上,這意味着它實現IANA   ISO_8859-1:1987代替了原來的ECMA-94:1985的代碼頁,這在離開0x00..0x1F和0x7F..0x9F範圍未定義)即,

>>> "".join(chr(c) for c in range(256)).encode('iso-8859-1') == bytes(range(256)) 
True 

因此,只要有二進制數據被錯誤地轉換爲Unicode,就可以用.encode('iso-8859-1')恢復原始數據。

注:以上所有代碼片段的Python 3

+0

我真的很感謝這個徹底的解釋,希望我能給更多的讚揚。 – Ropstah 2015-03-04 10:51:44

+0

我要開始使用Powershell來執行我的Python :) – Ropstah 2015-03-04 10:55:58

+0

@zwol:'UnicodeEncodeError,UnicodeDecodeError'除外:這會產生一個錯誤,使用這個Lign是不正確的,但是它只在'僅使用'時使用'for UnicodeEncodeError: ' – 2017-01-21 00:09:46

0

上Python3.5我的答覆工作,忽略所有maformed caracters,所以OBJECTIF是與在try集團打印打印正確的caracters,和除了你可以使用通過塊以外,或者打印它們並使用編碼進行編碼()

from codecs import open 
with open("C:/test2/trans1", "r", "utf-8") as f: 
    lines = f.readlines() 
    f.close() 
for ligne in lines: 
    try: 
     print(ligne.rstrip()) 
    except UnicodeEncodeError: 
     print(ligne.rstrip().encode())