2010-08-27 112 views
22

我有一張Excel電子表格,其中包含一些英鎊符號。UnicodeEncodeError:'ascii'編解碼器無法對字符進行編碼u' xa3'

當我嘗試使用xlrd模塊讀它,我得到以下錯誤:

x = table.cell_value(row, col) 
x = x.decode("ISO-8859-1") 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 0: ordinal not in range(128) 

如果我重寫這x.encode(「UTF-8」)將停止拋出一個錯誤,但不幸的是,當我將數據寫入其他地方(如latin-1)時,£符號全部變成亂碼。

我該如何解決這個問題,並正確讀取英鎊符號?

--- UPDATE ---

某種類型的讀者建議我並不需要它在所有解碼,或者說我可以只是將其編碼爲Latin-1的,當我需要。這樣做的問題是我最終需要將數據寫入CSV文件,並且似乎反對原始字符串。

如果我不編碼或數據都進行解碼,然後出現這種情況(後我已經添加了字符串數組稱爲項):

for item in items: 
    #item = [x.encode('latin-1') for x in item] 
    cleancsv.writerow(item) 
File "clean_up_barnet.py", line 104, in <module> 
cleancsv.writerow(item) 
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2022' in position 43: ordinal not in range(128) 

我得到同樣的錯誤,即使我取消對拉丁線1的評論。

+0

你是否'.decode'ing兩次? – katrielalex 2010-08-27 21:05:29

+0

我不這麼認爲。上一行是來自xlrd模塊的x = table.cell_value(row,col),雖然 - 也許這是在做一些有趣的事情? – AP257 2010-08-27 21:07:39

回答

9

您的代碼段說x.decode,但你得到的編碼錯誤 - 這意味着x是Unicode了,所以,以「解碼」,它必須先變成字節的字符串(而這正是默認編解碼器ansi出現並失敗)。在你的文本然後你說「如果我重寫ot到x。編碼」...這似乎意味着你知道x是Unicode。

那麼什麼是你正在做的 - 這是你的意思做 - 編碼的Unicode x得到字節編碼字符串,或字節的字符串解碼成Unicode字符集的對象?

我覺得很可惜,你可以調用一個Unicode對象encode一個字節串,並decode,因爲我覺得這樣似乎導致用戶只是混亂......但至少在這種情況下,你似乎管理傳播混亂(至少對我來說;-)。

如果,因爲它似乎,x是unicode的,那麼你永遠要「解碼」 - 你可能要編碼它得到一個字節串具有一定的編解碼器,例如latin-1,如果這就是你需要的某種I/O用途(對於你自己的內部程序使用,我建議始終堅持使用unicode - 只有當你絕對需要編碼/解碼需要接收,用於輸入/輸出目的的編碼字節串)。

+1

謝謝。我猜這是unicode - 但我需要對它進行編碼以將其寫入CSV文件。當我嘗試將其編碼爲拉丁文-1時,我收到另一個錯誤。請參閱我上面的更新... – AP257 2010-08-27 21:26:52

+1

想通了 - 在寫入CSV之前,我需要的行是item = [x.encode('mac_roman')for x in item]。接受這個答案,因爲它幫助我弄清楚發生了什麼 - 謝謝。 – AP257 2010-08-27 21:29:17

+0

@ alex-martelli我會很樂意在[這個問題]上得到你的建議(http://stackoverflow.com/questions/23013236/how-to-encode-xml-into-esri-shapefiles-using-python)。 – JJD 2014-04-11 13:01:44

2

xlrd適用於Unicode,所以你得到的字符串是一個Unicode字符串。 £ - 符號的代碼點爲U + 00A3,因此所述字符串的表示應爲u'\xa3'。這已被正確讀入;這是你應該在整個程序中使用的字符串。

當您在某處編寫此(抽象Unicode)字符串時,您需要選擇一種編碼。那時,你應該把.encode轉換成那個編碼,比如說latin-1


>>> book = xlrd.open_workbook("test.xls") 
>>> sh = book.sheet_by_index(0) 
>>> x = sh.cell_value(0, 0) 
>>> x 
u'\xa3' 
>>> print x 
£ 

# sample outputs (for e.g. writing to a file) 
>>> x.encode("latin-1") 
'\xa3' 
>>> x.encode("utf-8") 
'\xc2\xa3' 

# garbage, because x is already Unicode 
>>> x.decode("ascii") 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 0: 
ordinal not in range(128) 
>>> 
+0

請參閱我上面的更新:當我嘗試編碼它時,出現錯誤... – AP257 2010-08-27 21:26:33

10

對於它的價值:我的xlrd作者。

xlrd是否生成unicode?
選項1:閱讀第一屏xlrd文檔底部的Unicode部分:該模塊將所有文本字符串顯示爲Python unicode對象。
選項2:print type(text), repr(text)

你說「」「如果我重寫這x.encode(‘UTF-8’)停止拋出一個錯誤,但不幸的是,當我然後寫出來的數據在其他地方(如latin-1),這些英鎊符號都變成了亂碼。「」「當然,如果你將UTF-8編碼文本寫入期望latin1的設備,它將會出現亂碼。你期望什麼?

你在編輯中說:「」「即使我取消註釋Latin-1行」「,我也會得到相同的錯誤。這是不太可能的 - 更有可能的是,你在不同的源代碼行(未註釋的latin1行而不是writerow行)中獲得了稍微不同的錯誤(提到latin1編解碼器而不是ascii編解碼器)。仔細閱讀錯誤信息有助於理解。

這裏你的問題是,一般來說你的數據是不可編碼的latin1;很少有真實世界的數據。您的POUND SIGN可以用latin1進行編碼,但這不是全部的非ASCII數據。有問題的字符是U + 2022 BULLET,它不能用latin1編碼。

如果您在前面提到您正在使用Mac OS X時,它會幫助您更快得到更好的答案......適用於CSV的編碼的常見嫌疑人是cp1252(Windows),而不是mac-roman

+1

「仔細閱讀錯誤消息以幫助理解。」如果錯誤信息不是神祕的,則爲true。也許不在你的代碼中,但是那裏有很多錯誤信息,顯然從來沒有打算讀取,至少不是地球人 – Davos 2016-07-01 03:48:26

5
x = x.decode("ISO-8859-1") 
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa3' in position 0: ordinal not in range(128) 

仔細查看:你有一個Unicode編碼*** ***錯誤調用解碼方法。

原因是decode旨在將字節序列(str)轉換爲unicode對象。但是,正如John所說,xlrd已經使用了Unicode字符串,所以x已經是unicode對象。

在這種情況下,Python 2.x會假定您的意思是來解碼str對象,所以它會「幫助」爲您創建一個對象。但爲了將unicode轉換爲str,它需要一個編碼,並選擇ASCII,因爲它是字符編碼的最低公分母。您的代碼有效解釋爲

x = x.encode('ascii').decode("ISO-8859-1") 

由於x包含非ASCII字符而失敗。

由於x已經是unicode對象,因此decode是不必要的。但是,現在您遇到了Python 2.x csv模塊不支持Unicode的問題。您必須將您的數據轉換爲str對象。

for item in items: 
    item = [x.encode('latin-1') for x in item] 
    cleancsv.writerow(item) 

這將是正確的,除非你有字符(U + 2022 BULLET)在您的數據,以及Latin-1的不能代表它。有幾種方法解決此問題:

  • x.encode('latin-1', 'ignore')刪除子彈(或其他非拉丁-1字符)。
  • x.encode('latin-1', 'replace')用問號替換子彈。
  • 用拉丁-1字符替換項目符號,如*·
  • 使用字符編碼確實包含您需要的所有字符。

現在,UTF-8得到了廣泛的支持,因此沒有理由對文本文件使用任何其他編碼。

19

圍繞所有「'ascii'編解碼器無法編碼字符的一個非常簡單的方法...」與csvwriter的問題是改爲使用unicodecsv,csvwriter的替代品。

與PIP安裝unicodecsv然後你就可以在完全一樣的方式來使用它,例如:

import unicodecsv 
file = open('users.csv', 'w') 
w = unicodecsv.writer(file) 
for user in User.objects.all().values_list('first_name', 'last_name', 'email', 'last_login'): 
    w.writerow(user) 
0

與xlrd工作,我有一個線... xl_data.find(STR(CELL_VALUE)) ...給出錯誤:「'ascii'編解碼器無法對位置3中的字符u'\ xdf'進行編碼:序號不在範圍(128)中」。論壇中的所有建議對我的德語單詞都沒有用處。但改爲:... xl_data.find(cell.value)...沒有錯誤。所以,我想在某些命令中使用字符串作爲參數,而xldr具有特定的編碼問題。

相關問題