UnicodeEncodeError: кодек 'ascii' не может кодировать символ u '\ xa3'
У меня есть таблица Excel, которую я читаю, в которой содержатся некоторые знаки.
Когда я пытаюсь прочитать его при использовании модуля 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 ---
Некоторые читатели предположили, что мне вообще не нужно его декодировать, или что я могу просто закодировать его на латинском языке 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.
Ответы
Ответ 1
В вашем фрагменте кода x.decode
, но вы получаете ошибку encode - значение x
уже есть Unicode, поэтому, чтобы "декодировать" его, он должен быть сначала преобразован в строка байтов (и то, где появляется кодек ansi
по умолчанию). В вашем тексте вы скажете "если я переписал ot на x. encode"... что, по-видимому, означает, что вы do знаете, что x является Unicode.
Итак, что вы делаете - и что вам нужно означает - кодирование unicode x
, чтобы получить закодированную строку байтов или декодировать строку байтов в объект unicode?
Мне посчастливилось называть encode
в байтовой строке и decode
на объекте unicode, потому что я считаю, что это приводит к тому, что пользователи не приводят к путанице... но по крайней мере в этом случае вы похоже, удается распространять путаницу (по крайней мере, для меня; -).
Если, как кажется, x
является unicode, вы никогда не захотите его "декодировать" - вы можете закодировать его, чтобы получить строку байта с определенным кодеком, например. latin-1, если это то, что вам нужно для каких-то целей ввода-вывода (для использования вашей собственной внутренней программы я рекомендую постоянно придерживаться unicode - только кодировать/декодировать, если и когда вам абсолютно нужна или получать, закодированные строки байтов для ввода/вывода).
Ответ 2
Очень простой способ обойти все кодеки "ascii" не может кодировать символ... "Проблемы с csvwriter состоят в том, чтобы вместо этого использовать unicodecsv, замена для csvwriter.
Установите unicodecsv с помощью pip, а затем вы можете использовать его точно так же, например:
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)
Ответ 3
Для чего это стоит: я автор 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; очень мало реальных данных. Ваш ЗНАК ЗВУКА кодируется в latin1, но это не все ваши данные, отличные от ASCII. Проблематичным является U + 2022 BULLET, который не кодируется в latin1.
Это помогло бы вам получить лучший ответ раньше, если бы вы упомянули фронт, что вы работаете в Mac OS X... обычным подозреваемым для CSV-подходящей кодировки является cp1252
(Windows), а не mac-roman
.
Ответ 4
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
, поэтому он "помогает" создает его для вас. Но для преобразования a 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')
, чтобы удалить пулю (или другие символы не латинского алфавита).
- Напишите
x.encode('latin-1', 'replace')
, чтобы заменить маркер вопросительным знаком.
- Замените пули символом Latin-1, например
*
или ·
.
- Используйте кодировку символов, которая содержит все необходимые символы.
В наши дни UTF-8 широко поддерживается, поэтому нет смысла использовать любую другую кодировку для текстовых файлов.
Ответ 5
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)
>>>
Ответ 6
Работа с xlrd, у меня есть в строке... xl_data.find(str (cell_value))... которая дает ошибку: "кодек ascii не может кодировать символ u '\ xdf' в позиции 3: порядковый номер не в диапазоне (128)". Все предложения на форумах бесполезны для моих немецких слов. Но переход на:... xl_data.find(cell.value)... не дает ошибок. Итак, я полагаю, что использование строк в качестве аргументов в некоторых командах с xldr имеет специфические проблемы с кодировкой.