1

我正在尝试使用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 完全是错误的方法。

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

4

1 回答 1

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 代码放在配置文件末尾的好处是代码中的任何内容都不会与您在其余部分中使用的格式发生冲突的文件。

于 2013-05-03T18:20:05.120 回答