【问题标题】:Reading raw section with ConfigParser使用 ConfigParser 读取原始部分
【发布时间】:2013-05-03 16:22:06
【问题描述】:

我正在尝试使用ConfigParser 模块来处理几乎完全为.ini 格式的文件。我想知道是否可以阅读“原始”部分,我只是在该部分中获取全文。如果不可能,我想知道是否有另一种“标准”方法(带有内置模块)来处理这种类型的文件,可能包括 shlex 或标准中的类似内容图书馆。

我查看了ConfigParser 的来源,看起来文本在任何地方都没有“原始”存储,所以我猜这是不可能的。

我认为我尝试解析的文件示例会有所帮助。我想要一个包含 3 个部分的文件:

[load]
files=a,b,c

[process]
<raw python code>

[export]
files=x,y,z

这个想法是加载/导出部分是 ConfigParser 模块假定的确切格式/行为。但是,process 部分需要作为原始 Python 代码阅读。用户将根据从load 部分中的文件加载的数据,将需要执行多次的原始代码放在这里。

这不是最复杂的格式,所以我可以轻松编写自己的解析器。如果需要,我还可以将文件格式更改为不是 .ini 样式。我只想为用户提供拥有多个部分和“原始”Python 代码部分的能力。也许 ConfigParser 完全是错误的方法。

我宁愿不为此编写自己的解析器,因为它看起来与现有格式非常相似。但是,如果它更适合,我可以轻松选择另一种“标准”格式。我只是不知道其他这样的格式。

【问题讨论】:

  • 请注意 [export]files=x,y,z 在 Python 中都是有效的表达式,那么您将如何确定 [process] 部分的结尾?我认为这里的答案是 ConfigParser 不合适,不幸的是,除非您可以对 &lt;raw python code&gt; 施加一些限制。
  • @Aya 我认为你是对的。我相信我可以假设[export] 实际上是[process] 部分的结尾。但是,它仍然有点 hack。

标签: python


【解决方案1】:

好吧,如果您准备假设 [process] 始终在 [export] 之前,并且 [export] 将始终标记 Python 代码的结尾,那么您可以预处理 ini 文件以去除它在将其传递给 ConfigParser 之前的部分...

from ConfigParser import RawConfigParser
from StringIO import StringIO

START_PROCESS_TOKEN = '[process]'
END_PROCESS_TOKEN = '[export]'

def hacky_parse(stream):
    state = 0
    ini_io = StringIO()
    python_io = StringIO()
    for line in stream.readlines():
        if state == 0:
            if line.strip() == START_PROCESS_TOKEN:
                state = 1
                continue
            ini_io.write(line)
        elif state == 1:
            if line.strip() == END_PROCESS_TOKEN:
                ini_io.write(line)
                state = 2
                continue
            python_io.write(line)
        else:
            ini_io.write(line)

    ini_io.seek(0)
    python_io.seek(0)

    config_parser = RawConfigParser()
    config_parser.readfp(ini_io)

    python_code = python_io.getvalue()

    return config_parser, python_code


cfg = """
[load]
files=a,b,c

[process]
while 1:
    do_stuff()

[export]
files=x,y,z
"""

my_stream = StringIO(cfg)
config_parser, process_code = hacky_parse(my_stream)
print 'The value of "files" in section "load" is...'
print config_parser.get('load', 'files')
print
print 'The raw Python code is...'
print process_code

...产生...

The value of "files" in section "load" is...
a,b,c

The raw Python code is...
while 1:
    do_stuff()

...显然,将my_stream 替换为类似...的真实文件对象

my_stream = open('config.ini', 'r')

更新

好吧,你的代码更有可能被破坏,例如,如果 [load] 行出现在 Python 代码中。

我只是想到了另一种选择。如果您使配置文件看起来像 RFC822 消息...

Load-Files: a,b,c
Export-Files: x,y,z

# Python code starts here
while 1:
    do_stuff()

...您可以像这样非常简单地解析它...

import email

cfg = \
"""Load-Files: a,b,c
Export-Files: x,y,z

# Python code starts here
while 1:
    do_stuff()
"""

msg = email.message_from_string(cfg)
print msg.items()
print
print msg.get_payload()

..产生...

[('Load-Files', 'a,b,c'), ('Export-Files', 'x,y,z')]

# Python code starts here
while 1:
    do_stuff()

我的意思是,您不必使用严格的 RFC822 格式,但将 Python 代码放在配置文件末尾的好处是代码中的任何内容都不会与您使用的格式发生冲突文件的其余部分。

【讨论】:

  • 该解决方案肯定会奏效。我实际上想出了this。我认为您的性能可能会更好一些,因为您不会两次阅读[process] 部分。但是,性能在这里并不是一个大问题,如果不进行分析,就无法确定任何事情。解决方案中是否还有其他值得注意的差异?
  • 我喜欢使用 RFC822 格式的想法。 import email解析文件非email文件感觉有点奇怪,但确实让解析更容易。
  • @durden2.0 好吧,您也可以使用rfc822 模块,但它已被弃用。
猜你喜欢
  • 2022-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 1970-01-01
相关资源
最近更新 更多