解析现有配置文件
我有一个配置文件,格式如下:
protocol sample_thread {
{ AUTOSTART 0 }
{ BITMAP thread.gif }
{ COORDS {0 0} }
{ DATAFORMAT {
{ TYPE hl7 }
{ PREPROCS {
{ ARGS {{}} }
{ PROCS sample_proc }
} }
} }
}
这个文件可能没有这些确切的字段,而且我希望在解析之前,不用先告诉解析器数据的结构。
我查找过其他的配置文件解析器,但我找到的似乎都无法处理这种语法的文件。
我在寻找一个可以解析这种文件的模块,有什么建议吗?
如果有人好奇的话,这个文件是由Quovadx Cloverleaf生成的。
8 个回答
我来试着回答一下我认为缺失的问题……
配置文件有很多种格式。常见的格式有 *.ini 文件或者 Apache 配置文件,这些格式通常有很多解析工具可以使用。
还有一些自定义格式。你的文件看起来就是这种格式(可能是某种我们都没见过的特定格式,但在你搞清楚之前,这并不重要)。
我建议你先看看这个文件是从哪个软件生成的,看看他们是否提供了可以加载或生成这些文件的编程接口。如果没有明显的线索,可以给 Quovadx 打个电话,可能有人已经解决了这个问题。
否则,你可能需要自己动手写一个解析器。
如果你的示例文件能代表完整的格式,写一个解析器其实并不会太难。这个格式是一个值的层级结构,每个节点可以包含一个值或者一个子层级的值。一旦你定义了值可以包含的基本类型,解析器的结构就会非常简单。
你可以使用像 Lex/Flex 这样的工具,或者直接用你选择的编程语言写一个简单的解析器,这样可以比较快地完成。
在Brian的pyparsing解决方案基础上,你可以通过使用Dict类来创建一个类似反序列化的工具,用于处理这种格式:
import pyparsing
string = pyparsing.CharsNotIn("{} \t\r\n")
# use Word instead of CharsNotIn, to do whitespace skipping
stringchars = pyparsing.printables.replace("{","").replace("}","")
string = pyparsing.Word( stringchars )
# define a simple integer, plus auto-converting parse action
integer = pyparsing.Word("0123456789").setParseAction(lambda t : int(t[0]))
group = pyparsing.Forward()
group << ( pyparsing.Group(pyparsing.Literal("{").suppress() +
pyparsing.ZeroOrMore(group) +
pyparsing.Literal("}").suppress())
| integer | string )
toplevel = pyparsing.OneOrMore(group)
sample = """
protocol sample_thread {
{ AUTOSTART 0 }
{ BITMAP thread.gif }
{ COORDS {0 0} }
{ DATAFORMAT {
{ TYPE hl7 }
{ PREPROCS {
{ ARGS {{}} }
{ PROCS sample_proc }
} }
} }
}
"""
print toplevel.parseString(sample).asList()
# Now define something a little more meaningful for a protocol structure,
# and use Dict to auto-assign results names
LBRACE,RBRACE = map(pyparsing.Suppress,"{}")
protocol = ( pyparsing.Keyword("protocol") +
string("name") +
LBRACE +
pyparsing.Dict(pyparsing.OneOrMore(
pyparsing.Group(LBRACE + string + group + RBRACE)
) )("parameters") +
RBRACE )
results = protocol.parseString(sample)
print results.name
print results.parameters.BITMAP
print results.parameters.keys()
print results.dump()
输出结果是
['protocol', 'sample_thread', [['AUTOSTART', 0], ['BITMAP', 'thread.gif'], ['COORDS',
[0, 0]], ['DATAFORMAT', [['TYPE', 'hl7'], ['PREPROCS', [['ARGS', [[]]], ['PROCS', 'sample_proc']]]]]]]
sample_thread
thread.gif
['DATAFORMAT', 'COORDS', 'AUTOSTART', 'BITMAP']
['protocol', 'sample_thread', [['AUTOSTART', 0], ['BITMAP', 'thread.gif'], ['COORDS', [0, 0]], ['DATAFORMAT', [['TYPE', 'hl7'], ['PREPROCS', [['ARGS', [[]]], ['PROCS', 'sample_proc']]]]]]]
- name: sample_thread
- parameters: [['AUTOSTART', 0], ['BITMAP', 'thread.gif'], ['COORDS', [0, 0]], ['DATAFORMAT', [['TYPE', 'hl7'], ['PREPROCS', [['ARGS', [[]]], ['PROCS', 'sample_proc']]]]]]
- AUTOSTART: 0
- BITMAP: thread.gif
- COORDS: [0, 0]
- DATAFORMAT: [['TYPE', 'hl7'], ['PREPROCS', [['ARGS', [[]]], ['PROCS', 'sample_proc']]]]
我觉得用pyparsing会让你更快地取得进展。
-- Paul
pyparsing 是一个非常方便的工具,可以用来快速简单地解析数据。最基本的用法大概是这样的:
import pyparsing
string = pyparsing.CharsNotIn("{} \t\r\n")
group = pyparsing.Forward()
group << pyparsing.Group(pyparsing.Literal("{").suppress() +
pyparsing.ZeroOrMore(group) +
pyparsing.Literal("}").suppress())
| string
toplevel = pyparsing.OneOrMore(group)
使用方法如下:
>>> toplevel.parseString(text)
['protocol', 'sample_thread', [['AUTOSTART', '0'], ['BITMAP', 'thread.gif'],
['COORDS', ['0', '0']], ['DATAFORMAT', [['TYPE', 'hl7'], ['PREPROCS',
[['ARGS', [[]]], ['PROCS', 'sample_proc']]]]]]]
从这里开始,你可以根据需要变得更加复杂(比如把数字和字符串分开解析,查找特定的字段名等等)。上面的例子比较通用,只是寻找字符串(定义为任何非空格的字符,除了 "{" 和 "}")以及用 {} 括起来的字符串列表。