3

parseStringが正しい結果をもたらす場合に、scanStringを機能させるのに問題があります。

このシーケンスは機能します:

alpha_rev = pyp.Word(pyp.alphas, max=2)
num_rev = pyp.Word('123456789', max=2)
space = pyp.White(ws=" ").suppress()

revisionExpr = (
    pyp.StringStart().leaveWhitespace() +
    space +
    pyp.Combine(alpha_rev + 
    pyp.Optional(num_rev)("rev"))
    )

rev_string = ' K        WI, This is the title'

for match_str, start, end in (
    revisionExpr.scanString(rev_string, maxMatches=1)):
    print match_str

['K']

「Rev」または「Rev」がある場合があります。改訂前; これは失敗します:

revisionExpr = (
    pyp.StringStart().leaveWhitespace() +
    space +
    pyp.Combine(alpha_rev + 
    pyp.Optional(num_rev)("rev"))
    |
    pyp.CaselessLiteral("Rev") + pyp.Optional('.') + 
    pyp.Combine(alpha_rev + 
    pyp.Optional(num_rev)("rev"))
    )

for match_str, start, end in (
    revisionExpr.scanString(rev_string, maxMatches=1)):
    print match_str

print match_str
NameError: name 'match_str' is not defined

「|」はなぜですか 試合を失敗させますか?これは、最初の例と2番目の例の両方で機能することに注意してください。

revisionTokens = revisionExpr.parseString(rev_string)

最後の例の2番目の部分(「|」の後)を最初の例のような形式に抽出すると、「Rev」を追加すると機能します。rev_stringの「K」の前。残念ながら、最初の式の先頭の空白は、リビジョン文字列を一意に識別するために必要です。そうでない場合、この例では「WI」が一致します。

parseStringの代わりにscanStringを使用しようとしています。これは、一致の開始位置と終了位置を返すため、後の処理に役立ちます。

4

1 に答える 1

2

問題は、「or」演算子 (「|」) がその左右の要素のみを直接見ていることです。文法要素が正しくグループ化されていません。これがあなたの文法をもう少し分解したものです:

left_expr = pyp.Combine(alpha_rev + pyp.Optional(num_rev)("rev")
right_expr = pyp.CaselessLiteral("Rev")

joined_expr = left_expr | right_expr

final_expr = (pyp.StringStart().leaveWhitespace() +
    space +
    joined_expr +
    pyp.Optional('.') +
    pyp.Combine(alpha_rev +
      pyp.Optional(num_rev)("rev"))
    )

ご覧のとおり、これは望んでいたものではありません。テキスト "Rev" または実際のリビジョンのいずれかを検索し、その後に別のリビジョンが続きます。式の修正版は次のとおりです。

revisionExpr = (
    pyp.StringStart().leaveWhitespace() +
    space +
    (
        pyp.Combine(alpha_rev +
            pyp.Optional(num_rev)("rev")
        )
        |
        (
            pyp.CaselessLiteral("Rev") + 
            pyp.Optional('.') +
            pyp.Combine(alpha_rev +
                pyp.Optional(num_rev)("rev"))
        )
    )
)

ただし、文法をもう少し簡潔にすることができます。

revisionExpr = (
    pyp.StringStart().leaveWhitespace() +
    space +
    pyp.Suppress(
        pyp.Optional(
            pyp.CaselessLiteral("Rev") + 
            pyp.Optional('.')
        )
    ) +
    pyp.Combine(
        alpha_rev +
        pyp.Optional(num_rev)("rev")
    )
)

このバージョンでは、「Rev.」のみをマークします。リビジョンまたは "Rev." のみを解析するオプションを解析に与えるのではなく、予期される位置にオプションとしてテキストを追加します。+ リビジョン。これにより、「|」の使用に起因する問題が回避されます。オペレーター。

PyParsing は演算子のオーバーロードを使用してより適切な構文を提供することを忘れないでください。構文が混乱を引き起こす場合 (このシナリオのように)、「pyp.Or(a, b)」のような長い形式のメソッド呼び出しを使用する方がよい場合があります。 .

于 2012-11-07T05:19:20.303 に答える