使用Unicode项的ConfigParser

27 投票
5 回答
36970 浏览
提问于 2025-04-15 15:31

我在使用ConfigParser的时候遇到了一些麻烦。它似乎对Unicode的支持不是很好。虽然配置文件是以UTF-8格式保存的,但当ConfigParser读取这个文件时,似乎把它编码成了其他格式。我原以为是latin-1编码,所以我想通过重写optionxform来解决这个问题:

-- 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',但这似乎没什么意义,因为它本来就应该是一个Unicode对象。毕竟,配置文件是UTF-8格式的,对吧?我通过用这个DummyConfig类来测试,确认了ConfigParser读取文件的方式有问题。如果我使用这个类,那么一切都是很好的Unicode,没问题。

-- 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()

5 个回答

2

试着像这样重写 RawConfigParser() 中的 write 函数:

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")
17

在Python 3.2版本中,给read()函数增加了一个叫encoding的参数,这样我们现在可以这样使用它:

cfg.read("myconfig", encoding='utf-8')
22

ConfigParser.readfp()这个方法可以接收一个文件对象,你有没有试过先用codecs模块以正确的编码打开这个文件对象,然后再把它传给ConfigParser,像下面这样:

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

对于Python 3.2及以上版本,readfp()这个方法已经不推荐使用了。建议使用read_file()来代替。

撰写回答