注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

Tsecer的回音岛

Tsecer的博客

 
 
 

日志

 
 

python对ini文件的解析  

2018-01-06 20:08:09|  分类: python |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
一、python源代码中对于配置文件的解析
可以看到,对于文件内容的解析都是通过正则表达式实现的,并且配置文件只有两种形式:一种是节(section)的定义,另一种是节中配置项的赋值。而对于section的解析表达式位于SECTCRE中,下面的OPTCRE表示不允许出现非空配置项的正则表达式,OPTCRE_NV是表示允许出现配置项为空的正则表达式(NV明显是No Value的首字母缩写)。

Python-2.7.13\Lib\ConfigParser.py
    #
    # Regular expressions for parsing section headers and options.
    #
    SECTCRE = re.compile(
        r'\['                                 # [
        r'(?P<header>[^]]+)'                  # very permissive!
        r'\]'                                 # ]
        )
    OPTCRE = re.compile(
        r'(?P<option>[^:=\s][^:=]*)'          # very permissive!
        r'\s*(?P<vi>[:=])\s*'                 # any number of space/tab,
                                              # followed by separator
                                              # (either : or =), followed
                                              # by any # space/tab
        r'(?P<value>.*)$'                     # everything up to eol
        )
    OPTCRE_NV = re.compile(
        r'(?P<option>[^:=\s][^:=]*)'          # very permissive!
        r'\s*(?:'                             # any number of space/tab,
        r'(?P<vi>[:=])\s*'                    # optionally followed by
                                              # separator (either : or
                                              # =), followed by any #
                                              # space/tab
        r'(?P<value>.*))?$'                   # everything up to eol
        )

二、python中使用的正则表达式

这个表达式中比较诡异的就是其中的 "?P<option>" 这样的表达式形式
(?P<name>...)

Similar to regular parentheses, but the substring matched by the group is accessible via the symbolic group name name. Group names must be valid Python identifiers, and each group name must be defined only once within a regular expression. A symbolic group is also a numbered group, just as if the group were not named.

Named groups can be referenced in three contexts. If the pattern is (?P<quote>['"]).*?(?P=quote) (i.e. matching a string quoted with either single or double quotes):

Context of reference to group “quote”Ways to reference it
in the same pattern itself
  • (?P=quote) (as shown)
  • \1
when processing match object m
  • m.group('quote')
  • m.end('quote') (etc.)
in a string passed to the repl argument of re.sub()
  • \g<quote>
  • \g<1>
  • \1

如果抛开这个语法cookie,后面的正则表达式就比较简单了。这里的表达式每行表示一个部分,第一行就像分组中的名字option所描述的,就是表示选项的名称,vi表示分隔符(为什么叫vi,猜测可能是 value indicator),最后一行是配置的value值。

    OPTCRE = re.compile(
        r'(?P<option>[^:=\s][^:=]*)'          # very permissive!
        r'\s*(?P<vi>[:=])\s*'                 # any number of space/tab,
                                              # followed by separator
                                              # (either : or =), followed
                                              # by any # space/tab
        r'(?P<value>.*)$'                     # everything up to eol
        )
在OPTCRE_NV版本中,最后 r'(?P<value>.*))?$' 中的“?”对应的就是可选的由来,也就是这个值可以为空。

三、配置文件解析中的tag使用
这里面就通过每个匹配group的tag名字来获得每个子匹配的内容
optname, vi, optval = mo.group('option', 'vi', 'value')

    def _read(self, fp, fpname):
……
                    mo = self._optcre.match(line)
                    if mo:
                        optname, vi, optval = mo.group('option', 'vi', 'value')
                        optname = self.optionxform(optname.rstrip())
                        # This check is fine because the OPTCRE cannot
                        # match if it would set optval to None
                        if optval is not None:
                            if vi in ('=', ':') and ';' in optval:
                                # ';' is a comment delimiter only if it follows
                                # a spacing character
                                pos = optval.find(';')
                                if pos != -1 and optval[pos-1].isspace():
                                    optval = optval[:pos]
                            optval = optval.strip()
                            # allow empty values
                            if optval == '""':
                                optval = ''
                            cursect[optname] = [optval]
                        else:
                            # valueless option handling
                            cursect[optname] = optval
……

四、测试下基础功能
1、在没有使能 non value 的情况下
配置文件中的lue值为空时直接解析报错
tsecer@harry: cat ini.ini 
[sec]
var=1
lue

tsecer@harry: cat confp.py
import ConfigParser

conf = ConfigParser.ConfigParser()
conf.read("./ini.ini")
print conf.items("sec")

tsecer@harry: python confp.py
Traceback (most recent call last):
  File "confp.py", line 4, in <module>
    conf.read("./ini.ini")
  File "/usr/lib64/python2.7/ConfigParser.py", line 305, in read
    self._read(fp, filename)
  File "/usr/lib64/python2.7/ConfigParser.py", line 546, in _read
    raise e
ConfigParser.ParsingError: File contains parsing errors: ./ini.ini
[line  3]: 'lue\n'
tsecer@harry: 

2、添加allow_no_value=True
tsecer@harry: cat confp.py
import ConfigParser

conf = ConfigParser.ConfigParser(allow_no_value=True)
conf.read("./ini.ini")
print conf.items("sec")

tsecer@harry: python confp.py
[('var', '1'), ('lue', None)]
tsecer@harry: 

3、allow_no_value选项的版本要求 
allow_no_value=True 这个选项在早期的版本中不一定存在,我是在新的python版本中测试的,至少我使用2.6.6版本中还没有这个选项
tsecer@harry: python --version
Python 2.6.6
tsecer@harry: cat confp.py 
import ConfigParser

conf = ConfigParser.ConfigParser(allow_no_value=True)
conf.read("./ini.ini")
print conf.items("sec")
tsecer@harry: python ./confp.py 
Traceback (most recent call last):
  File "./confp.py", line 3, in <module>
    conf = ConfigParser.ConfigParser(allow_no_value=True)
TypeError: __init__() got an unexpected keyword argument 'allow_no_value'
tsecer@harry: 
我测试成功使用的是
tsecer@harry: python --version
Python 2.7.5

  评论这张
 
阅读(29)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018