2010-08-27 4 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») он перестает бросать ошибку, но, к сожалению, когда я записываю данные где-то в другом месте (как латинский-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) 

я получаю ту же ошибку, даже если я раскомментируйте линию Latin-1.

+0

Вы '.decode'-ing дважды? – katrielalex

+0

Я так не думаю. Предыдущая строка: x = table.cell_value (строка, col), из модуля xlrd, хотя, может быть, это что-то смешное? – AP257

ответ

9

Ваш фрагмент кода говорит x.decode, но вы получать закодировать ошибки - это означает, x Юникод уже, так, чтобы «расшифровывать» его, он должен быть первым превратился в строку байт (и где по умолчанию появляется кодек ansi). В вашем тексте вы говорите: «Если я переписал ot на x. encode« ... что, кажется, подразумевает, что вы do знаете, что это x Unicode.

Так что это вы делаете - и что это ты значишь быть делать - кодирующей Юникоду x, чтобы получить закодированную строку байт или декодирование строки байт в объект Юникода?

Я считаю, что жаль, что вы можете вызвать encode на строку байтов и decode на объекте юникода, потому что я считаю, что, кажется, ведет пользователей к чему, кроме путаницы ... но, по крайней мере, в этом случае вы, кажется, управлять распространять путаницу (по крайней мере, для меня ;-).

Если, как это кажется, x это юникод, то вы никогда не хотите «расшифровывает» это - вы можете закодировать его, чтобы получить байты строки с определенным кодеком, например, latin-1, если это то, что вам нужно для каких-то целей ввода-вывода (для вашей собственной внутренней программы я рекомендую придерживаться unicode все время - только кодировать/декодировать, если и когда вам абсолютно нужен, или получить, кодированные байтовые строки для ввода/вывода).

+1

Спасибо. Я предполагаю, что это unicode, но мне нужно закодировать его, чтобы записать его в файл CSV. Когда я пытаюсь закодировать его в латинском-1, я получаю еще одну ошибку. Пожалуйста, см. Мое обновление выше ... – AP257

+1

Выяснил это - строка, которая мне нужна, прежде чем писать в CSV, была item = [x.encode ('mac_roman') для x в элементе]. Принимая этот ответ, потому что он помог мне разобраться в происходящем - спасибо. – AP257

+0

@ alex-martelli Я был бы рад получить ваш совет по [этому вопросу] (http://stackoverflow.com/questions/23013236/how-to-encode-xml-into-esri-shapefiles-using-python). – JJD

2

xlrd работает с Unicode, поэтому строка, которую вы возвращаете, является строкой Unicode. E-знак имеет кодовую точку 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

см. Мое обновление выше: я получаю сообщение об ошибке, когда пытаюсь .encode ... – AP257

10

Для чего это стоит: Я автор xlrd.

xlrd Производить unicode?
Вариант 1: прочитайте раздел Юникод в нижней части первого экрана xlrd doc: Этот модуль представляет все текстовые строки как объекты юникода Python.
Вариант 2: print type(text), repr(text)

Вы говорите, что «» "Если бы я переписать это x.encode („UTF-8“) он перестает бросать ошибку, но, к сожалению, когда я затем записать данные из где-то еще (как латинский-1), знаки «все» стали искаженными ».« Конечно, если вы напишете текст с кодировкой UTF-8 на устройство, ожидающее latin1, оно будет искажено. Что вы ожидали?

Вы говорите в своем правлении: "" "Я получаю ту же ошибку, даже если я раскомментирую латинскую линию 1" "". Это очень маловероятно - гораздо вероятнее, что вы получили немного другую ошибку (упоминание кодека latin1 вместо кодека ascii) в другой исходной строке (раскоментированная строка latin1 вместо строки writow). Чтение сообщений об ошибках тщательно помогает пониманию.

Ваша проблема заключается в том, что в целом ваши данные НЕ кодируются в latin1; очень мало реальных данных. Ваш POUND SIGN кодируется в latin1, но это не все ваши данные, отличные от ASCII. Проблематичным является U + 2022 BULLET, который не кодируется в latin1.

Это помогло бы вам получить лучший ответ раньше, если бы вы упомянули, что вы работаете в Mac OS X ... обычным подозреваемым для CSV-подходящей кодировки является cp1252 (Windows), а не mac-roman.

+1

«Чтение сообщений об ошибках тщательно помогает пониманию». Истина, когда сообщение об ошибке не является загадочным. Возможно, не в вашем коде, но есть много сообщений об ошибках, которые явно никогда не предназначались для чтения, по крайней мере, не для землян – Davos

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 *** Encode *** Ошибка вызова декодирования метод.

Причина этого заключается в том, что decode предназначен для преобразования из последовательности байтов (str) в объект unicode. Но, как сказал Джон, 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'), чтобы удалить пулю (или других не-Latin-1 символов).
  • Напишите x.encode('latin-1', 'replace'), чтобы заменить пулю вопросительным знаком.
  • Заменить пули на латинский символ 1, например * или ·.
  • Используйте кодировку символов, которую делает, содержит все необходимые символы.

В настоящее время UTF-8 широко поддерживается, поэтому нет причин использовать любую другую кодировку для текстовых файлов.

19

Очень простой способ обойти все кодеки «ascii» не может кодировать символ ... »Проблемы с csvwriter состоят в том, чтобы вместо этого использовать unicodecsv, замену для csvwriter.

Установите 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 (ул (CELL_VALUE)) ... который дает ошибку: «'ascii' codec не может кодировать символ u '\ xdf' в позиции 3: порядковый номер не в диапазоне (128)". Все предложения на форумах бесполезны для моих немецких слов. Но переход на: ... xl_data.find (cell.value) ... не дает ошибок. Итак, я полагаю, что использование строк в качестве аргументов в некоторых командах с xldr имеет специфические проблемы с кодировкой.