使用Unicode项的ConfigParser
我在使用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()
来代替。