Python UnicodeDecodeError: кодек ascii не может декодировать байт 0xc3

Я читаю файл конфигурации в разделах получения python и создаю новые файлы конфигурации для каждого раздела.

Однако... Я получаю сообщение об ошибке декодирования, поскольку одна из строк содержит Español=spain

self.output_file.write( what.replace( " = ", "=", 1 ) )
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)

Как бы я отрегулировал свой код, чтобы разрешить такие закодированные символы? Я очень новичок в этом, поэтому, пожалуйста, извините меня, если это что-то простое.

class EqualsSpaceRemover:
    output_file = None
    def __init__( self, new_output_file ):
        self.output_file = new_output_file

    def write( self, what ):
        self.output_file.write( what.replace( " = ", "=", 1 ) )

def get_sections():
    configFilePath = 'C:\\test.ini'
    config = ConfigParser.ConfigParser()
    config.optionxform = str
    config.read(configFilePath)
    for section in config.sections():
        configdata = {k:v for k,v in config.items(section)}
        confignew = ConfigParser.ConfigParser()
        cfgfile = open("C:\\" + section + ".ini", 'w')
        confignew.add_section(section)
        for x in configdata.items():
            confignew.set(section,x[0],x[1])
        confignew.write( EqualsSpaceRemover( cfgfile ) )
        cfgfile.close()

person Ranga Sarin    schedule 29.08.2016    source источник
comment
проверьте, работает ли what.replace( " = ", "=", 1 ).encode('utf-8')   -  person mic4ael    schedule 29.08.2016
comment
Я только что проверил, и это дало мне следующее: self.output_file.write( what.replace( " = ", "=", 1 ).encode('utf-8') ) UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)   -  person Ranga Sarin    schedule 29.08.2016
comment
Удалить первую строку (+ создать с помощью utf-8)!   -  person dsgdfg    schedule 29.08.2016
comment
Извините, если я туплю, но что вы имеете в виду? это первый раз, когда я работал с кодировкой   -  person Ranga Sarin    schedule 29.08.2016
comment
что, если вы откроете файл с помощью utf-8? как 2_   -  person mic4ael    schedule 29.08.2016
comment
Мне это кажется python2. Если это так, добавьте соответствующий тег, так как обработка юникода в python2 и python3 совершенно различна. Вы используете from __future__ import unicode_literals? Это объясняет, почему вы получаете UnicodeDecodeError.   -  person mata    schedule 29.08.2016
comment
@ mic4eal, который по-прежнему выдавал ту же ошибку. @mata вы правы, и удаление from __future__ import unicode_literals устранило проблему! Большое спасибо.   -  person Ranga Sarin    schedule 29.08.2016


Ответы (1)


Если вы используете python2 с from __future__ import unicode_literals, то каждый строковый литерал, который вы пишете, является литералом Unicode, как если бы вы добавляли к каждому литералу префикс u"...", если вы явно не пишете b"...".

Это объясняет, почему вы получаете ошибку UnicodeDecodeError в этой строке:

what.replace(" = ", "=", 1)

потому что то, что вы на самом деле делаете,

what.replace(u" = ",u"=",1 )

ConfigParser использует старый добрый str для своих элементов при чтении файла с использованием метода parser.read(), что означает, что what будет str. Если вы используете юникод в качестве аргументов для str.replace(), тогда строка преобразуется (декодируется) в юникод, применяется замена и результат возвращается как юникод. Но если what содержит символы, которые не могут быть декодированы в Unicode с использованием кодировки по умолчанию, вы получите ошибку UnicodeDecodeError, которую не ожидаете.

Итак, чтобы выполнить эту работу, вы можете

  • использовать явные префиксы для байтовых строк: what.replace(b" = ", b"=", 1)
  • или удалите unicode_litreals будущий импорт.

Как правило, вы не должны смешивать unicode и str (python3 исправляет это, делая ошибку почти в любом случае). Вы должны знать, что from __future__ import unicode_literals изменяет каждый литерал без префикса на юникод и не изменяет автоматически ваш код для работы с юникодом во всех случаях. Как раз наоборот во многих случаях.

person mata    schedule 29.08.2016
comment
Это не похоже на правильный способ решения проблемы. Это решение игнорирует кодировку текста и надеется на лучшее. Лучшее решение — убедиться, что файлы конфигурации (как для чтения, так и для записи) открываются с правильной кодировкой символов (которая выглядит как utf-8 [согласно удаленному ответу OP]). По умолчанию py2 использует кодировку ОС по умолчанию (которая отличается от utf-8). - person Dunes; 29.08.2016
comment
@Dunes — в python2 ConfigParser не предполагает какой-либо кодировки в файле конфигурации, он читается как двоичный файл (по крайней мере, при использовании метода read(path)), а данные хранятся внутри в виде байтов (str) и записываются обратно как байты. Вы можете использовать что-то вроде parser.readfp(codecs.open(path, encoding='utf-8')), тогда юникод будет использоваться для всего, но, как и многие другие модули, он предназначен и задокументирован для использования с str. В python3 другая история, там работает только с юникодом. - person mata; 29.08.2016