我正在尝试使用 pyparsing 实现(可选)嵌套函数语法。使用像here这样的简单语法,我很快就启动并运行了它。
我的语法是这样定义的:
fnc = pp.Forward()
arg = pp.quotedString | pp.Word(pp.alphanums) | fnc # + ' []:=&!*#$/+'
fnc << pp.Group(pp.Word('!$#&') + pp.Word(pp.alphanums) + pp.Literal('(') + pp.Optional(pp.delimitedList(arg)) + pp.Literal(')'))
因此,根据我通过测试收集的信息,
quotedString
可以匹配任何类型的文本,没有任何问题,并且空格也可以正确处理。上面的 fnc
解析器几乎可以处理任何事情。例如 "&foo(arg1, arg2)"
(指向 pp.Word(pp.alphanums)
)或 "&foo('$Test,*Option1', &foo(arg2))"
(第一个参数指向 quotedString
。这里额外的符号 "$,*"
我相信是由 QuotedString 处理的,尽管我没有在某处明确定义它们。第二个参数指向 fnc
)。
当我写的内容没有用引号括起来时,我的问题就出现了。例如,考虑一个带有关键字参数的函数:
&foo(1,2.5,3.635, mode='multiply', decimals=3)
。这已经引发了一个异常,它是 expecting ")" (at char 8)
,因为上面的 arg
中没有定义该点。 (如果我将每个参数放在引号中,则此示例有效!)
因此,我开始通过添加我想要解析的所有特殊字符来使
arg
变得越来越明确:
arg = pp.quotedString | pp.Word(pp.alphanums + ' \'[].:=&!*#$/+') | fnc
现在的问题是,当我这样做时,函数递归会中断。示例
"&foo('$arg1', &foo(arg2))"
抛出异常 expecting ")" (at char 18)
(就在内部 foo
之后)。在上面的符号中包含括号最终会到达字符串的末尾,但它总是在最后一个位置中断,再次期待“)”。
我尝试通过使用
pp.printables
并排除括号来解决这个问题:
arg = pp.quotedString | pp.Word(pp.printables, excludeChars="()") | fnc
但这会产生类似的结果。 这就是我的问题。是否有像
quotedString
这样的东西(正则表达式类型或其他类型)可以开箱即用,但适用于不带引号的字符串?我预先感谢您提供任何指示/解决方案。
正如在所引用问题的答案中一样,您可能会明确列出语法元素,如
import pyparsing as pp
test_str1 = "&foo(1,2.5,3.635, mode='multiply', decimals=3)"
test_str2 = "&foo('$arg1', &foo(arg2))"
fnc = pp.Forward()
literal = pp.quotedString | pp.common.number | pp.Word(pp.alphanums)
kw = literal + '=' + literal
arg = fnc | kw | literal
fnc <<= pp.Group(pp.Word('!$#&') + pp.Word(pp.alphanums) + '(' + pp.Optional(pp.delimitedList(arg)) + ')'\
)
print(list(fnc.scanString(test_str1)))
print(list(fnc.scanString(test_str2)))
这给了
[(ParseResults([ParseResults(['&', 'foo', '(', 1, 2.5, 3.635, 'mode', '=', "'multiply'", 'decimals', '=', 3, ')'], {})], {}), 0, 46)]
[(ParseResults([ParseResults(['&', 'foo', '(', "'$arg1'", ParseResults(['&', 'foo', '(', 'arg2', ')'], {}), ')'], {})], {}), 0, 25)]