2015-07-08 2 views
0

Я пытаюсь записать текст и кодировать его в UTF-8, где это возможно, используя следующий код:питон UTF-8 кодирование бросает UnicodeDecodeError несмотря на «ошибки =" заменить»

outf.write((lang_name + "," + (script_name or "") + "\n").encode("utf-8", errors='replace')) 

I «получаю следующее сообщение об ошибке:

File "C:\Python27\lib\encodings\cp1252.py", line 15, in decode 
    return codecs.charmap_decode(input,errors,decoding_table) 
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 6: character maps to <undefined> 

Я думал errors='replace' часть моего кодирования вызова будет справиться с этим?

FWIW, я просто открыть файл с

outf = open(outfile, 'w') 

без явного объявления кодировки.

print repr(outf) 

производит:

<open file 'myfile.csv', mode 'w' at 0x000000000315E930> 

Я отделен заявление на запись в отдельную конкатенациях, кодирование и запись файл:

outstr = lang_name + "," + (script_name or "") + "\n" 
encoded_outstr = outstr.encode("utf-8", errors='replace') 
outf.write(encoded_outstr) 

Это конкатенация, что бросает исключение.

струны через print repr(foo)

lang_name: 'G\xc4\x81ndh\xc4\x81r\xc4\xab' 
script_name: u'Kharo\u1e63\u1e6dh\u012b' 

Далее детективной работы показывает, что я могу сцепить либо один из них с простой ASCII строки без каких-либо трудностей - это положить их обоих в той же строке, что ломать вещи ,

+1

Что такое 'script_code' и' script_name' здесь? У вас есть ** ошибка декодирования **, а не кодировка, поэтому один или оба являются байтами, а не объектами unicode. –

+1

'.encode (" utf-8 ")' в строке Unicode всегда будет работать, поскольку все точки Unicode могут быть представлены как UTF8, поэтому в этом случае 'errors = 'replace'' является излишним. – RemcoGerlich

+0

Далее, что такое 'outf' здесь? Как вы открыли этот объект? Что ваш код пытается декодировать bytestring *, поскольку CP1252 * является подозрительным. Для неявных декодирования это означает, что вы использовали 'sys.setdefaultencoding()' (большое значение no-no), но если 'outf' не является обычным файловым файлом Python 2, а вместо него является файлом' codecs' или 'io', который объясните это исключение. –

ответ

1

Итак, проблема заключается в том, что вы объединяете байты 'G\xc4\x81ndh\xc4\x81r\xc4\xab' и строку Unicode u'Kharo\u1e63\u1e6dh\u012b'.

Чтобы это сделать, Python 2.7 пытается декодировать байтовое кодирование с использованием его кодировки по умолчанию, чтобы превратить его в Unicode. Ваша кодировка по умолчанию - cp1252 вместо ASCII, по причинам, о которых я не могу знать, но в любом случае это не так, как если бы это был ASCII, потому что эта строка - UTF8.

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

Если вы не можете, так как вы кодировании UTF8 на следующей строке в любом случае, это, вероятно, проще всего кодировать только SCRIPT_NAME:

encoded_outstr = lang_name + b"," + (script_name.encode('utf-8') or b"") + b"\n" 

Следует заметить, что я использовал b"," явно сделать эти строковые литералы байтовых строк и не строки Unicode; если вы используете from __future__ import unicode_literals для совместимости с Python 3, то они по умолчанию Unicode, и проблема будет возникать снова.

+0

проблема в том, что я не думаю, что кодировки согласованы для каждой итерации цикла (!). Есть ли программный способ проверить, что такое кодировка? Я вроде бы думаю, что это открытый исследовательский вопрос ;-) – PurpleVermont

1

Когда вы объединяете строку байтов и строку Unicode, Python 2 пытается сначала преобразовать байтовую строку в Unicode. Если строка байтов содержит любые символы, отличные от ASCII, в диапазоне от \x80 до \xff, автоматическое преобразование завершится с ошибкой, которую вы покажете. Обратите внимание, что он говорит can't decode, а не can't encode - это показывает, что ошибка не произошла в вашем обращении к encode.

Решение должно содержать decode байтовую строку в Unicode, используя соответствующую кодовую страницу, так что все входы в конкатенацию являются строками Unicode.

outstr = lang_name.decode("utf-8") + u"," + (script_name or u"") + u"\n"