2015-01-23 3 views
0

Я пытался использовать csv.DictReader для разбора UTF-8 данные с помощью специальных символов, но я получаю следующее сообщение об ошибке:unicodecsv.DictReader не работает с io.StringIO (Python 2.7)

UnicodeEncodeError: 'ascii' codec can't encode character u'\xe3' in position 2: ordinal not in range(128) 

Я прочитал онлайн и выяснили, что библиотека csv Python 2.7 не обрабатывает Unicode. Я искал альтернативную библиотеку и нашел unicodecsv.

Я заменил csv на unicodecsv, но я получаю ту же ошибку. Вот упрощенная версия моего кода:

from io import StringIO 
from unicodecsv import DictReader, Dialect, QUOTE_MINIMAL 

data = (
    'first_name,last_name,email\r' 
    'Elmer,Fudd,[email protected]\r' 
    'Jo\xc3\xa3o Ant\xc3\xb4nio,Ara\xc3\xbajo,[email protected]\r' 
) 

unicode_data = StringIO(unicode(data, 'utf-8-sig'), newline=None) 

class CustomDialect(Dialect): 
    delimiter = ',' 
    doublequote = True 
    escapechar = '\\' 
    lineterminator = '\r\n' 
    quotechar = '"' 
    quoting = QUOTE_MINIMAL 
    skipinitialspace = True 

rows = DictReader(unicode_data, dialect=CustomDialect) 

for row in rows: 
    print row 

Если я заменяю StringIO с BytesIO, кодирование работает, но я не могу отправить newlines аргумент больше, и тогда я получаю:

Error: new-line character seen in unquoted field - do you need to open the file in universal-newline mode? 

ли кто-нибудь любая идея, как я мог это решить? Не следует ли использовать unicodecsv для StringIO? Спасибо

ответ

0

Я открыл an issue на странице gibub unicodecsv, и оказалось, что читатель unicodecsv ожидает байтовое кодирование, а не объект unicode.

Потратив некоторое время на то, чтобы сделать все это с Юникодом и кодировками в моей голове, оказалось, что мне действительно не нужен уникодекш в первую очередь. В конце концов, начальная проблема заключается в том, что io.StringIO, когда он повторяется с .next(), возвращал объекты unicode в csv.DictReader, который ожидал bytestrings. Так что, если unicodecsv также ожидает, что он будет ошибкой, он, очевидно, не сможет решить проблему.

Мое решение изменяло файл-подобный объект я проходивший в csv.DictReader так, чтобы он вернулся правильно закодированные байтовых строки вместо Юникода объектов:

class UTF8EncodedStringIO(StringIO): 
    def next(self): 
     return super(UTF8EncodedStringIO, self).next().encode('utf-8') 

udata = UTF8EncodedStringIO(unicode(data, 'utf-8-sig'), newline=None) 

Написав эту простую обертку StringIO вместо использования BytesIO Я мог бы решить проблемы с кодированием и получить прибыль от аргумента newline. Накладные расходы на декодирование/кодирование немного, но у меня не было альтернатив. Если у кого-то есть лучшее предложение, не стесняйтесь делиться.

Смежные вопросы