zoukankan      html  css  js  c++  java
  • python2.7 内置ConfigParser支持Unicode读写

    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)      # True
    12 print isinstance(u, unicode)  # True
    13 
    14 print s.__class__   # <type 'str'>
    15 print u.__class__   # <type 'unicode'>stryu

    前面的申明:# -*- coding: utf-8 -*- 表明,上面的 Python 代码由 utf-8 编码。
    两个 Python 字符串类型间可以用 encode / decode 方法转换:

    1 # 从 str 转换成 unicode
    2 print s.decode('utf-8')   # 关关雎鸠
    3 
    4 # 从 unicode 转换成 str
    5 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                  # 'xb9xd8xb9xd8xf6xc2xf0xaf'
     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'u934fu51b2u53e7u95c6u5ea8设定

     为什么 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'u5173u5173u96ceu9e20u5173u5173u96ceu9e20'
    17 
    18 # 同样没问题
    19 "中文:%s" % u   # u'u4e2du6587uff1au5173u5173u96ceu9e20'
    20 
    21 # 还是没问题
    22 u"中文:%s" % s  # u'u4e2du6587uff1au5173u5173u96ceu9e20'
    setdefaultencoding

    可以看到,问题魔术般的解决了。但是注意! sys.setdefaultencoding() 的效果是全局的,如果你的代码由几个不同编码的 Python 文件组成,用这种方法只是按下了葫芦浮起了瓢,让问题变得复杂。
    另一个陷阱是有关标准输出的。(另一个陷阱跟本文章关系不大,请参考这一节的原文:http://in355hz.iteye.com/blog/1860787

    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/2014
    10 # Copyright:   (c) ZWW 2014
    11 # Licence:     <your licence>
    12 #-------------------------------------------------------------------------------
    13 import codecs
    14 import ConfigParser
    15 import types
    16 import sys
    17 
    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 section
    32         file.write("[%s]
    " % section)
    33         for (key, value) in config.items(section):
    34             if key == "__name__":
    35                 continue
    36             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 value
    47             file.write("
    ")
    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 value
    57 
    58     str='中文'
    59     print str
    60     print type(str)
    61     print repr(str)
    62 
    63     utf8str = str.decode('utf-8')
    64     print utf8str
    65     print type(utf8str)
    66     print repr(utf8str)
    67 
    68     ini_set("section","option",utf8str)
    test.py

    执行完程序后输出如下:

     1 1 >>> 
     2 2 中文字符串
     3 3 涓�枃
     4 4 <type 'str'>
     5 5 'xe4xb8xadxe6x96x87'
     6 6 中文
     7 7 <type 'unicode'>
     8 8 u'u4e2du6587'
     9 9 >>> 
    10 output of test.py
    Output of test.py

    新的cfg.ini内容如下:

  • 相关阅读:
    Linux IO接口 监控 (iostat)
    linux 防火墙 命令
    _CommandPtr 添加参数 0xC0000005: Access violation writing location 0xcccccccc 错误
    Visual Studio自动关闭
    Linux vsftpd 安装 配置
    linux 挂载外部存储设备 (mount)
    myeclipse 9.0 激活 for win7 redhat mac 亲测
    英文操作系统 Myeclipse Console 乱码问题
    Linux 基本操作命令
    linux 查看系统相关 命令
  • 原文地址:https://www.cnblogs.com/zhaoweiwei/p/ConfigParser.html
Copyright © 2011-2022 走看看