我试图对一个包含以下一个或多个模式的字符串进行解析。
例如,我将使用以下字符串。
-flag1 -flag2 object2 { -nested_flag1 nested_obj1 -nested_flag2 }
为了解析它,我使用:
exp = '-flag1 -flag2 object2 { -nested_flag1 nested_obj1 -nested_flag2 }'
only_flag = '-' + Word(printables, excludeChars='-').setResultsName("flag")
flag_w_obj = only_flag + Optional("{") + Word(printables, excludeChars='-').setResultsName("object")
flag_w_obj_w_nested = flag_w_obj + originalTextFor(nestedExpr("{", "}")).setResultsName("nested_expr")
parser = flag_w_obj_w_nested | flag_w_obj | only_flag
parsed = parser.searchString(exp)
我如何用同样的规则来评估嵌套表达式 以获得嵌套的标志和对象?
我最终想要的结果是制作一个包含格式数据的dict。
{
"flag1": null,
"flag2": {
"object1": {
"nested_flag1": "nested_obj1",
"nested_flag2": null
}
}
}
大多数情况下,每当你有一个包含嵌套内容的表达式时,你最终会使用一个pyparsing Forward
表达方式。A Forward
允许您引用一个尚未完全定义的表达式--它是一个正向声明。在您的解析器中, -flag args...
形式本身可以包含嵌套在{}中的标志。一旦内容被指定,那么 "赋值 "就可以通过使用 <<=
操作符。
我还强烈建议在你开始实际编写任何代码之前,先写一个简短的解析器设计(无论你打算使用什么解析库,都要这样做)。在解析中,BNF(Backus-Naur Form)是典型的使用格式。它不一定要超严格,但要有足够的细节,这样你就可以手动完成它,以确保你有正确的碎片,并且没有歧义。也好写出一些你期望解析器能够处理的例子字符串。
下面的注释代码显示了我针对你的问题写出的BNF,以及将它实现到pyparsing解析器中的情况。
"""
BNF
flag_name := '-' alphanumeric...
flag_arg_word := alphanumeric...
flag_arg := flag_arg_word | '{' flag_expr... '}'
flag_expr := flag_name [flag_arg...]
"""
import pyparsing as pp
# define punctuation
LBRACE, RBRACE = map(pp.Suppress, "{}")
# recursive parser requires a forward declaraction
flag_expr = pp.Forward()
# implement BNF definitions
flag_name = pp.Word("-", pp.alphanums + "_")
flag_arg_word = pp.Word(pp.alphas, pp.alphanums + "_")
flag_arg = flag_arg_word | (LBRACE + flag_expr[...] + RBRACE)
# use '<<=' operator to define recursive expression
flag_expr <<= pp.Group(flag_name + pp.Group(flag_arg[...]))
# a command is 0 or more flag_exprs
cmd_expr = flag_expr[...]
# test it out
cmd = "-flag1 -flag2 object2 { -nested_flag1 nested_obj1 -nested_flag2 }"
parsed = cmd_expr.parseString(cmd)
# convert to a list and show with pprint
from pprint import pprint
pprint(parsed.asList(), width=12)
# runTests is very useful for running several test strings through a parser
cmd_expr.runTests("""\
-flag1 -flag2 object2 { -nested_flag1 nested_obj1 -nested_flag2 }
""")