UnicodeDecodeError при использовании Python 2.x unicodecsv
Я пытаюсь записать CSV-файл с символами Unicode, поэтому я использую пакет Unicodecsv. К сожалению, я все еще получаю UnicodeDecodeErrors:
# -*- coding: utf-8 -*-
import codecs
import unicodecsv
raw_contents = 'He observes an “Oversized Gorilla” near Ashford'
encoded_contents = unicode(raw_contents, errors='replace')
with codecs.open('test.csv', 'w', 'UTF-8') as f:
w = unicodecsv.writer(f, encoding='UTF-8')
w.writerow(["1", encoded_contents])
Это обратная связь:
Traceback (most recent call last):
File "unicode_test.py", line 11, in <module>
w.writerow(["1", encoded_contents])
File "/Library/Python/2.7/site-packages/unicodecsv/__init__.py", line 83, in writerow
self.writer.writerow(_stringify_list(row, self.encoding, self.encoding_errors))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/codecs.py", line 691, in write
return self.writer.write(data)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/codecs.py", line 351, in write
data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xef in position 17: ordinal not in range(128)
Я думал, что преобразование его в Unicode будет достаточно хорошим, но, похоже, это не так. Мне бы очень хотелось понять, что происходит, чтобы я лучше подготовился к устранению этих ошибок в других проектах в будущем.
Из трассировки, похоже, я могу воспроизвести ошибку следующим образом:
>>> raw_contents = 'He observes an “Oversized Gorilla” near Ashford'
>>> raw_contents.encode('UTF-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 15: ordinal not in range(128)
>>>
До сих пор я думал, что у меня есть неплохие рабочие знания по работе с текстом Unicode в Python 2.x, но это смутило меня.
1 ответ
Вы не должны использовать codecs.open()
для вашего файла. unicodecsv
оборачивает csv
модуль, который всегда записывает байтовую строку в открытый объект файла. Чтобы записать эту байтовую строку в файловый объект с поддержкой Unicode, например, возвращенный codecs.open()
неявно декодируется; это где ваш UnicodeDecodeError
исключение проистекает из.
Вместо этого используйте файл в двоичном режиме:
with open('test.csv', 'wb') as f:
w = unicodecsv.writer(f, encoding='UTF-8')
w.writerow(["1", encoded_contents])
Бинарный режим не является строго обязательным, если только ваши данные не содержат встроенных символов новой строки, но csv
Модуль хочет контролировать, как пишутся символы новой строки, чтобы гарантировать правильную обработку таких значений. Однако, не используя codecs.open()
это абсолютное требование.
То же самое происходит, когда вы звоните .encode()
на байтовой строке; вы уже там закодировали данные, поэтому Python неявно декодирует, чтобы получить значение Unicode для кодирования.