単一の大きな方法を使用してパーサーを作成する方法と、現在の方法で段階的に使用する方法のどちらでも構いません。
スリット (「サプレス リテラル」だと思います)、stringtolits、decimaltable などの便利なヘルパー ユーティリティがいくつか定義されていることがわかります。これは私には良さそうです。
結果名を使用していることが気に入っています。これにより、解析後のコードの堅牢性が大幅に向上します。pyparsing 1.4.7 で追加されたショートカット フォームを使用することをお勧めします。
busname.setResultsName("bus1")
と
busname("bus1")
これにより、コードがかなり整理されます。
解析アクションを振り返って、個々のトークンにアクセスするために数値インデックスを使用している場所を確認し、戻って代わりに結果の名前を割り当てます。GetStats が を返す 1 つのケースを次に示します(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()))
全体として、これはこの複雑さのファイルとほぼ同等だと思います。私はあなたが持っているのと同じようにコードを断片的に構築した同様のフォーマットを持っています(残念ながら独自のものなので共有できません)が、1つの大きなメソッドでは、次のようなものです:
def parser():
header = Group(...)
inputsummary = Group(...)
jobstats = Group(...)
measurements = Group(...)
return header("hdr") + inputsummary("inputs") + jobstats("stats") + measurements("meas")
Group コンストラクトは、解析されたデータの各セクション内で結果名の一種の名前空間を確立するために、このような大規模なパーサーで特に役立ちます。