我可以选择使用单一的大方法来创建解析器,而不是像现在这样逐步进行。
我可以看到您已经定义了一些有用的辅助实用程序,例如 slot(我猜是“suppress Literal”)、stringtolits 和 decimaltable。这对我来说看起来不错。
我喜欢您使用结果名称,它们确实提高了解析后代码的稳健性。我建议使用 pyparsing 1.4.7 中添加的快捷方式,您可以在其中替换
busname.setResultsName("bus1")
与
busname("bus1")
这可以让你的代码更加整洁。
我会回顾您的解析操作,看看您在哪里使用数字索引来访问单个标记,然后返回并分配结果名称。这是一种情况,GetStats 返回(ngroup + sgroup).setParseAction(self.process_stats)。 process_stats 的引用如下:
self.num_load = tokens[0]["loads"]
self.num_generator = tokens[0]["generators"]
self.num_transformer = tokens[0]["transformers"]
self.num_line = tokens[0]["lines"]
self.num_bus = tokens[0]["buses"]
self.power_rate = tokens[1]["rate"]
我喜欢您对值和统计信息进行了分组,但请继续为它们命名,例如“network”和“soln”。然后您可以将此解析操作代码编写为(我还转换为 - 对我而言 - 更易于阅读的对象属性表示法,而不是 dict 元素表示法):
self.num_load = tokens.network.loads
self.num_generator = tokens.network.generators
self.num_transformer = tokens.network.transformers
self.num_line = tokens.network.lines
self.num_bus = tokens.network.buses
self.power_rate = tokens.soln.rate
还有一个风格问题:为什么有时使用显式 And 构造函数,而不是使用 '+' 运算符?
busdef = And([busname.setResultsName("bus1"),
busname.setResultsName("bus2"),
integer.setResultsName("linenum"),
decimaltable("pf qf pl ql".split())])
这写起来也很简单:
busdef = (busname("bus1") + busname("bus2") +
integer("linenum") +
decimaltable("pf qf pl ql".split()))
总的来说,我认为对于这种复杂性的文件来说,这是差不多的。我有一个类似的格式(不幸的是,专有的,所以不能共享),我以类似于你的方式构建代码,但是在一个大的方法中,像这样:
def parser():
header = Group(...)
inputsummary = Group(...)
jobstats = Group(...)
measurements = Group(...)
return header("hdr") + inputsummary("inputs") + jobstats("stats") + measurements("meas")
Group 构造在像这样的大型解析器中特别有用,可以为解析数据的每个部分中的结果名称建立一种命名空间。