3

私は pyparsing を使用していますが、MongoDB からデータ フィールドを抽出し、単純な算術演算を実行できる単純な DSL を開発するのに優れていることがわかりました。私は現在、Rank[Person:Height] 形式の関数をフィールドに適用し、単純な式を関数呼び出しの引数として含めることができるようにツールを拡張しようとしています。解析構文を機能させるのに苦労しています。これが私がこれまでに持っているものです:

# Define parser
expr = Forward()
integer = Word(nums).setParseAction(EvalConstant)
real = Combine(Word(nums) + "." + Word(nums)).setParseAction(EvalConstant)

# Handle database field references that are coming out of Mongo, 
# accounting for the fact that some fields contain whitespace
dbRef = Combine(Word(alphas) + ":" + Word(printables) + \
    Optional(" " + Word(alphas) + " " + Word(alphas)))
dbRef.setParseAction(EvalDBref)

# Handle function calls
functionCall = (Keyword("Rank") | Keyword("ZS") | Keyword("Ntile")) + "[" + expr + "]"
functionCall.setParseAction(EvalFunction)
operand =  functionCall | dbRef | (real | integer) 

signop = oneOf('+ -')
multop = oneOf('* /')
plusop = oneOf('+ -')

# Use parse actions to attach Eval constructors to sub-expressions
expr << operatorPrecedence(operand,
    [
     (signop, 1, opAssoc.RIGHT, EvalSignOp),
     (multop, 2, opAssoc.LEFT, EvalMultOp),
     (plusop, 2, opAssoc.LEFT, EvalAddOp),
    ])

私の問題は、Rank[Person:Height] のような単純な式をテストすると、解析例外が発生することです。

ParseException: Expected "]" (at char 19), (line:1, col:20)

Rank[3 + 1.1] のような引数として float または算術式を使用すると、解析は正常に機能し、dbRef 文法を単純化して Word(alphas) だけでも機能します。私の一生の間、私の完全な文法の何が問題なのかを理解することはできません. オペランドの順序を並べ替えたり、functionCall 文法を単純化しようとしましたが、役に立ちませんでした。誰かが私が間違っていることを見ることができますか?

これが機能するようになったら、最後の一歩を踏み出し、式での変数代入のサポートを導入したいと思います..

編集:さらにテストすると、dbRef 文法から印刷可能なものを削除すると、問題なく動作します:

 dbRef = Combine(Word(alphas) + OneOrMore(":") + Word(alphanums) + \
      Optional("_" + Word(alphas)))

ただし、文字「-」を dbRef (「Class:SN」などの DB フィールドに必要) に追加すると、パーサーが再び失敗します。operatorPrecedence の signop によって「-」が消費されていると思いますか?

4

2 に答える 2

2

発生しているように見える]のは、テスト文字列の末尾の文字 ( Rank[Person:Height]) がトークンの一部として消費されるdbRefことです。これは、このトークンのイニシャルを過ぎた部分:が Word(printables) (およびこの文字セット、残念ながら、角括弧文字が含まれています)

次に、パーサーは を生成しようとしますfunctionCallが、終了が欠落している]ため、エラー メッセージが表示されます。

暫定的な修正は、角括弧を含まない文字セットを使用することです。おそらく、次のようなより明示的なものです。

dbRef = Combine(Word(alphas) + ":" + Word(alphas, alphas+"-_./") + \
    Optional(" " + Word(alphas) + " " + Word(alphas)))

編集
よく見ると、上記は大まかに正しいですが、トークン階層が間違っています(たとえば、パーサーfunctionCallが an の 1 つのオペランドとしてa を生成しようとするexpr など)。また、記号
のあいまいさのために、提案された修正は機能しませんこれは、 内では普通の文字として、 内では plusOp として-理解されるべきです。このタイプの問題はパーサーでは一般的であり、これに対処する方法がありますが、pyparsing で正確にどのように行うかはわかりません。dbRefexpr

于 2012-11-28T00:14:08.870 に答える
0

解決策が見つかりました-問題は、dbRef の文法が関数仕様の一部である文字の一部を消費していたことです。正しく機能する新しい文法:

dbRef = Combine(Word(alphas) + OneOrMore(":") + Word(alphanums) + \
    Optional(oneOf("_ -") + Word(alphas)))
于 2012-11-28T01:06:52.310 に答える