pyparsing SkipTo 和 key = value 输入

pyparsing SkipTo and key = value input

我正在尝试使用 pyparsing 定义输入解析器。我已经设法正确解析了如下内容:

key = value

其中值可以是,例如整数。这是 Python 代码:

import pyparsing as pp

_name = pp.Word(pp.alphas + '_', pp.alphanums + '_')
_key = _name + EQ
_value = pp.pyparsing_common.signed_integer

pp.dictOf(_key, _value)

现在我想添加一个"raw"数据输入:

$raw
H 0.0 0.0 0.0
F 1.0 1.0 1.0
$end

其中 $$end 之间的任何内容都是 "gobbled up" 的字符串,其键为 raw。我试过:

import pyparsing as pp

SDATA = pp.Literal('$').suppress()
EDATA = pp.CaselessLiteral('$end').suppress()
data_t = pp.Combine(SDATA + pp.Word(pp.alphas + '_', pp.alphanums + '_')
                ) + pp.SkipTo(EDATA) + EDATA
data_t.setName('raw data')
data_t.setParseAction(lambda token: (token[0], token[1]))

这适用于输入字符串 '$raw\nH 0.0 0.0 0.0\nF 1.0 1.0 1.0\n$end' 但是,我无法设法将 key = value 解析器与 data_t 结合起来。我在这里遗漏了什么明显的东西吗?还是不能将两者结合起来?

更新

这是测试输入:

$raw
H 0.0 0.0 0.0
F 1.0 1.0 1.0
$end

int = 42

这就是我组合 key = value 和 "raw" 数据解析器的方式:

parser = pp.dictOf(_key, _value) ^ data_t

解析后调用为:

tokens = parser.parseString(keywords).asDict()

这个return一个空的dict。将 int = 42 移动到 $raw ... $end 上方 return 只是 {'int': 42 }.

哟哟!这部分是由于 dictOf 中的错误。为了在这方面取得进展,我定义了以下内容:

kv_dict = pp.Dict(pp.OneOrMore(pp.Group(_key + _value)))

然后我将解析器定义为:

parser = pp.OneOrMore(pp.Group(data_t) | pp.Group(kv_dict))

分组很重要,这样一组中的键就不会踩到另一组中的键。 (dictOf 中的错误阻止像这样将它包含在 OneOrMore 中,因为 dictOf 允许一个空的字典,所以它在字符串的末尾永远循环而不是终止。)

最后,我使用 dump() 而不是 asDict() 来查看结果。 asDict() 将只显示已命名的解析标记,而您的 data_t 不是。

print(parser.parseString(sample).dump())

给出:

[[('raw', 'H 0.0 0.0 0.0\nF 1.0 1.0 1.0\n')], [['int', 42]]]
[0]:
  [('raw', 'H 0.0 0.0 0.0\nF 1.0 1.0 1.0\n')]
[1]:
  [['int', 42]]
  - int: 42

如果要在 data_t 中添加名称,请将定义更改为此,并删除解析操作:

data_t = pp.Combine(SDATA + pp.Word(pp.alphas + '_', pp.alphanums + '_')
                )("name") + pp.SkipTo(EDATA)("body") + EDATA

现在我得到:

[['raw', 'H 0.0 0.0 0.0\nF 1.0 1.0 1.0\n'], [['int', 42]]]
[0]:
  ['raw', 'H 0.0 0.0 0.0\nF 1.0 1.0 1.0\n']
  - body: 'H 0.0 0.0 0.0\nF 1.0 1.0 1.0\n'
  - name: 'raw'
[1]:
  [['int', 42]]
  - int: 42