博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
python2.7 内置ConfigParser支持Unicode读写
阅读量:6498 次
发布时间:2019-06-24

本文共 6530 字,大约阅读时间需要 21 分钟。

1 python编码基础

对应 C/C++ 的 char 和 wchar_t, Python 也有两种字符串类型,str 与 unicode:

str与unicode
1 # -*- coding: utf-8 -*- 2 # file: example1.py 3 import string 4  5 # 这个是 str 的字符串 6 s = '关关雎鸠' 7  8 # 这个是 unicode 的字符串 9 u = u'关关雎鸠'10 11 print isinstance(s, str)      # True12 print isinstance(u, unicode)  # True13 14 print s.__class__   # 
15 print u.__class__ #
stryu

前面的申明:# -*- coding: utf-8 -*- 表明,上面的 Python 代码由 utf-8 编码。

两个 Python 字符串类型间可以用 encode / decode 方法转换:

1 # 从 str 转换成 unicode2 print s.decode('utf-8')   # 关关雎鸠3 4 # 从 unicode 转换成 str5 print u.encode('utf-8')   # 关关雎鸠
encode/decode转换

为什么从 unicode 转 str 是 encode,而反过来叫 decode? 

因为 Python 认为 16 位的 unicode 才是字符的唯一内码,而大家常用的字符集如 gb2312,gb18030/gbk,utf-8,以及 ascii 都是字符的二进制(字节)编码形式。把字符从 unicode 转换成二进制编码,当然是要 encode。

反过来,在 Python 中出现的 str 都是用字符集编码的 ansi 字符串。Python 本身并不知道 str 的编码,需要由开发者指定正确的字符集 decode。

(补充一句,其实 Python 是可以知道 str 编码的。因为我们在代码前面申明了 # -*- coding: utf-8 -*-,这表明代码中的 str 都是用 utf-8 编码的,我不知道 Python 为什么不这样做。)

如果用错误的字符集来 encode/decode 会怎样?

设置编解码字符集
1 # 用 ascii 编码含中文的 unicode 字符串 2 u.encode('ascii')  # 错误,因为中文无法用 ascii 字符集编码 3                    # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128) 4  5 # 用 gbk 编码含中文的 unicode 字符串 6 u.encode('gbk')  # 正确,因为 '关关雎鸠' 可以用中文 gbk 字符集表示 7                  # '\xb9\xd8\xb9\xd8\xf6\xc2\xf0\xaf' 8                  # 直接 print 上面的 str 会显示乱码,修改环境变量为 zh_CN.GBK 可以看到结果是对的 9 10 # 用 ascii 解码 utf-8 字符串11 s.decode('ascii')  # 错误,中文 utf-8 字符无法用 ascii 解码12                    # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)13 14 # 用 gbk 解码 utf-8 字符串15 s.decode('gbk')  # 不出错,但是用 gbk 解码 utf-8 字符流的结果,显然只是乱码16                  # u'\u934f\u51b2\u53e7\u95c6\u5ea8\设定

 为什么 Python 这么容易出现字符串编/解码异常? 

这要提到处理 Python 编码时容易遇到的两个陷阱。第一个是有关字符串连接的: 

1 # -*- coding: utf-8 -*- 2 # file: example2.py 3  4 # 这个是 str 的字符串 5 s = '关关雎鸠' 6  7 # 这个是 unicode 的字符串 8 u = u'关关雎鸠' 9 10 s + u  # 失败,UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)
字符串连接

 简单的字符串连接也会出现解码错误?

陷阱一:在进行同时包含 str 与 unicode 的运算时,Python 一律都把 str 转换成 unicode 再运算,当然,运算结果也都是 unicode。

由于 Python 事先并不知道 str 的编码,它只能使用 sys.getdefaultencoding() 编码去 decode。在我的印象里,sys.getdefaultencoding() 的值总是 'ascii' ——显然,如果需要转换的 str 有中文,一定会出现错误。

除了字符串连接,% 运算的结果也是一样的:

1 # 正确,所有的字符串都是 str, 不需要 decode 2 "中文:%s" % s   # 中文:关关雎鸠 3  4 # 失败,相当于运行:"中文:%s".decode('ascii') % u 5 "中文:%s" % u  # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128) 6  7 # 正确,所有字符串都是 unicode, 不需要 decode 8 u"中文:%s" % u   # 中文:关关雎鸠 9 10 # 失败,相当于运行:u"中文:%s" % s.decode('ascii')11 u"中文:%s" % s  # UnicodeDecodeError: 'ascii' codec can't decode byte 0xe5 in position 0: ordinal not in range(128)
%运算

其实,sys.getdefaultencoding() 的值是可以用“后门”方式修改的,我不是特别推荐这个解决方案,但是还是贴一下,因为后面有用:

1 # -*- coding: utf-8 -*- 2 # file: example3.py 3 import sys 4  5 # 这个是 str 的字符串 6 s = '关关雎鸠' 7  8 # 这个是 unicode 的字符串 9 u = u'关关雎鸠'10 11 # 使得 sys.getdefaultencoding() 的值为 'utf-8'12 reload(sys)                      # reload 才能调用 setdefaultencoding 方法13 sys.setdefaultencoding('utf-8')  # 设置 'utf-8'14 15 # 没问题16 s + u  # u'\u5173\u5173\u96ce\u9e20\u5173\u5173\u96ce\u9e20'17 18 # 同样没问题19 "中文:%s" % u   # u'\u4e2d\u6587\uff1a\u5173\u5173\u96ce\u9e20'20 21 # 还是没问题22 u"中文:%s" % s  # u'\u4e2d\u6587\uff1a\u5173\u5173\u96ce\u9e20'
setdefaultencoding

可以看到,问题魔术般的解决了。但是注意! sys.setdefaultencoding() 的效果是全局的,如果你的代码由几个不同编码的 Python 文件组成,用这种方法只是按下了葫芦浮起了瓢,让问题变得复杂。

另一个陷阱是有关标准输出的。(另一个陷阱跟本文章关系不大,请参考这一节的原文:)

2 python读写ini配置文件

以上介绍了基础python编解码知识,下面具体说明ConfigParser如果管理ini配置文件

配置文件编码为UTF-8,内容如下:

1 [section]2 option=中文字符串
cfg.ini

可以通过Notepad++来查看cfg.ini文件的编码方式

ConfigParser可以方便的读取ini配置文件,但是当重新写入时会遇到问题

1 import codecs 2 import ConfigParser 3  4 cfgfile="cfg.ini" 5  6 config = ConfigParser.ConfigParser() 7 config.readfp(codecs.open(cfgfile, "r", "utf-8")) 8 value = config.get("section","option") 9 #config.write(open("cfg2.ini", "w+"))10 config.write(codecs.open("cfg2.ini", "w+", "utf-8"))
write error

跟踪了一下,在ConfigParser模块的如下位置出现问题:

具体来说是str(value)出错了,因为在例子中的value值为“中文字符串”这已经超出ascii编码的处理范围,我的解决方法是重新实现写入操作,请参考代码:

1 #!/usr/bin/python 2 # -*- coding: utf-8 -*- 3 #------------------------------------------------------------------------------- 4 # Name: 5 # Purpose: 6 # 7 # Author:      ZWW 8 # 9 # Created:     19/01/201410 # Copyright:   (c) ZWW 201411 # Licence:     
12 #-------------------------------------------------------------------------------13 import codecs14 import ConfigParser15 import types16 import sys17 18 cfgfile="cfg.ini"19 20 def ini_set(sec,key,value):21 try:22 config.readfp(codecs.open(cfgfile, "r", "utf-8"))23 if not config.has_section(sec):24 temp = config.add_section(sec)25 config.set(sec, key, value)26 except Exception as e:27 print("error",str(e))28 file = codecs.open(cfgfile, "w", "utf-8")29 sections=config.sections()30 for section in sections:31 #print section32 file.write("[%s]\n" % section)33 for (key, value) in config.items(section):34 if key == "__name__":35 continue36 if type(value) in (type(u'') , type('')):37 file.write(key+"="+value)38 elif type(value) == type(1):39 optStr="%s=%d"%(key,value)40 file.write(optStr)41 elif type(value) == type(1.5):42 optStr="%s=%f"%(key,value)43 file.write(optStr)44 else:45 print "do not support this type"46 print value47 file.write("\n")48 file.close()49 50 if __name__=="__main__":51 config = ConfigParser.ConfigParser()52 config.readfp(codecs.open(cfgfile, "r", "utf-8"))53 value = config.get("section","option")54 #config.write(open("cfg2.ini", "w+"))55 #config.write(codecs.open("cfg2.ini", "w+", "utf-8"))56 print value57 58 str='中文'59 print str60 print type(str)61 print repr(str)62 63 utf8str = str.decode('utf-8')64 print utf8str65 print type(utf8str)66 print repr(utf8str)67 68 ini_set("section","option",utf8str)
test.py

执行完程序后输出如下:

1 1 >>>  2 2 中文字符串 3 3 涓枃 4 4 
5 5 '\xe4\xb8\xad\xe6\x96\x87' 6 6 中文 7 7
8 8 u'\u4e2d\u6587' 9 9 >>> 10 output of test.py
Output of test.py

新的cfg.ini内容如下:

 

 

 

 

转载于:https://www.cnblogs.com/zhaoweiwei/p/ConfigParser.html

你可能感兴趣的文章
.net内存管理与指针
查看>>
Maven学习(一) - Maven基础
查看>>
思科AP与交换机端口的配置
查看>>
深入浅出开源性能测试工具 Locust (使用篇 1)
查看>>
[ObjectiveC]NSDATA, NSDICTIONARY, NSSTRING互转
查看>>
php实现单链表
查看>>
js获取当前页面的URL信息
查看>>
idea的优秀博客推荐
查看>>
关于事务隔离级别
查看>>
Linux环境搭建 | 手把手教你安装Linux虚拟机
查看>>
Linux下如何查看版本信息
查看>>
MobSDK如何轻松实现App社会化功能及免费短信验证功能
查看>>
僵尸(bot)程序缓解
查看>>
【分布式共识三】拜占庭将军问题----书面协议
查看>>
java中Array和ArrayList区别
查看>>
MakeCode图形化编程语言学习笔记:micro:bit编程练习题[图]
查看>>
linux 防火墙 -netfilter
查看>>
自动化运维—saltstack
查看>>
Redis5.0之Stream案例应用解读
查看>>
PrestaShop 网站漏洞修复如何修复
查看>>