解析现有配置文件

4 投票
8 回答
2762 浏览
提问于 2025-04-15 12:15

我有一个配置文件,格式如下:

protocol sample_thread {
    { AUTOSTART 0 }
    { BITMAP thread.gif }
    { COORDS {0 0} }
    { DATAFORMAT {
        { TYPE hl7 }
        { PREPROCS {
            { ARGS {{}} }
            { PROCS sample_proc }
        } }
    } } 
}

这个文件可能没有这些确切的字段,而且我希望在解析之前,不用先告诉解析器数据的结构。

我查找过其他的配置文件解析器,但我找到的似乎都无法处理这种语法的文件。

我在寻找一个可以解析这种文件的模块,有什么建议吗?

如果有人好奇的话,这个文件是由Quovadx Cloverleaf生成的。

8 个回答

1

我来试着回答一下我认为缺失的问题……

配置文件有很多种格式。常见的格式有 *.ini 文件或者 Apache 配置文件,这些格式通常有很多解析工具可以使用。

还有一些自定义格式。你的文件看起来就是这种格式(可能是某种我们都没见过的特定格式,但在你搞清楚之前,这并不重要)。

我建议你先看看这个文件是从哪个软件生成的,看看他们是否提供了可以加载或生成这些文件的编程接口。如果没有明显的线索,可以给 Quovadx 打个电话,可能有人已经解决了这个问题。

否则,你可能需要自己动手写一个解析器。

如果你的示例文件能代表完整的格式,写一个解析器其实并不会太难。这个格式是一个值的层级结构,每个节点可以包含一个值或者一个子层级的值。一旦你定义了值可以包含的基本类型,解析器的结构就会非常简单。

你可以使用像 Lex/Flex 这样的工具,或者直接用你选择的编程语言写一个简单的解析器,这样可以比较快地完成。

2

在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

10

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']]]]]]]

从这里开始,你可以根据需要变得更加复杂(比如把数字和字符串分开解析,查找特定的字段名等等)。上面的例子比较通用,只是寻找字符串(定义为任何非空格的字符,除了 "{" 和 "}")以及用 {} 括起来的字符串列表。

撰写回答