2009-10-30 1 views
17

мои проблемы с ConfigParser продолжаются. Кажется, он не поддерживает Unicode очень хорошо. Конфигурационный файл действительно сохраняется как UTF-8, но когда ConfigParser читает его, он, похоже, кодируется во что-то другое. Я предположил, что это была латинская-1, и я thougt перекрывая optionxform может помочь:ConfigParser с элементами Unicode

-- configfile.cfg -- 
[rules] 
Häjsan = 3 
☃ = my snowman 

-- myapp.py -- 
# -*- coding: utf-8 -*- 
import ConfigParser 

def _optionxform(s): 
    try: 
     newstr = s.decode('latin-1') 
     newstr = newstr.encode('utf-8') 
     return newstr 
    except Exception, e: 
     print e 

cfg = ConfigParser.ConfigParser() 
cfg.optionxform = _optionxform  
cfg.read("myconfig") 

Конечно, когда я прочитал конфигурации я получаю:

'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128) 

Я попробовал несколько различных вариантов декодирование «s», но дело, кажется спорным, так как это действительно должно быть юникода объект с самого начала. В конце концов, файл конфигурации UTF-8? Я подтвердил, что что-то не так в том, как ConfigParser читает файл, разбивая его на этот класс DummyConfig. Если я использую это, тогда все будет хорошо юникодом, прекрасным и денди.

-- config.py -- 
# -*- coding: utf-8 -*-     
apa = {'rules': [(u'Häjsan', 3), (u'☃', u'my snowman')]} 

class DummyConfig(object): 
    def sections(self): 
     return apa.keys() 
    def items(self, section): 
     return apa[section] 
    def add_section(self, apa): 
     pass 
    def set(self, *args): 
     pass 

Любые идеи, которые могут быть причиной этого или предложения других конфигурационных модулей, которые поддерживают Unicode лучше, приветствуются. Я не хочу использовать sys.setdefaultencoding()!

+0

Снеговик не является частью 'латино-1' – u0b34a0f6ae

+0

Никогда не делать' кроме Exception'; поймать фактическое исключение, которое вы знаете, как обращаться. –

ответ

19

Метод ConfigParser.readfp() может принимать объект файла, вы пробовали открывать объект файла с правильной кодировкой, используя модуль кодеков перед отправкой его на ConfigParser, как показано ниже:

cfg.readfp(codecs.open("myconfig", "r", "utf8")) 

Для Python 3.2 или выше, readfp() не рекомендуется. Вместо этого используйте read_file().

+1

У меня была такая же проблема, и я решил это сделать так же, как READ из конфигурационного файла. Но мне также нужно переписать модифицированную версию, и это не удается, даже если я использую codecs.open: 'с codecs.open (filename, encoding = ENCODING, mode = 'wb') как conffile: config.write (conffile) ' –

+0

Привет Ghislain, у меня такая же проблема с configparser, чтобы написать строку unicode. Он решен путем обновления его до последнего verb by pip. – Erxin

1

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

1

Кажется, проблема с версией ConfigParser для python 2x, и версия для 3x не содержит этой проблемы. С: this issue of the Python Bug Tracker, статус Закрыт + WONTFIX.

Я исправил его, отредактировав файл ConfigParser.py. В способе записи (около линии 412), изменить:

key = " = ".join((key, str(value).replace('\n', '\n\t'))) 

по

key = " = ".join((key, str(value).decode('utf-8').replace('\n', '\n\t'))) 

Я не знаю, если это реальное решение, но испытано в Windows 7 и Ubuntu 15.04, работает как очарование, и я могу делиться и работать с тем же .ini-файлом в обеих системах.

2

Попытка переписать функцию write в RawConfigParser() так:

class ConfigWithCoder(RawConfigParser): 
def write(self, fp): 
    """Write an .ini-format representation of the configuration state.""" 
    if self._defaults: 
     fp.write("[%s]\n" % "DEFAULT") 
     for (key, value) in self._defaults.items(): 
      fp.write("%s = %s\n" % (key, str(value).replace('\n', '\n\t'))) 
     fp.write("\n") 
    for section in self._sections: 
     fp.write("[%s]\n" % section) 
     for (key, value) in self._sections[section].items(): 
      if key == "__name__": 
       continue 
      if (value is not None) or (self._optcre == self.OPTCRE): 
       if type(value) == unicode: 
        value = ''.join(value).encode('utf-8') 
       else: 
        value = str(value) 
       value = value.replace('\n', '\n\t') 
       key = " = ".join((key, value)) 
      fp.write("%s\n" % (key)) 
     fp.write("\n") 
+0

Вы также можете обезвредить RawConfigParser: 'RawConfigParser.write = write' –