5

パイソンニスタ:

Pyparsing を使用して次の文字列を解析するとします。

'ABC_123_SPEED_X 123'

was はABC_123識別子です。SPEED_Xはパラメータで、123は値です。Pyparsing を使用して次の BNF を考えました。

Identifier = Word( alphanums + '_' )
Parameter = Keyword('SPEED_X') or Keyword('SPEED_Y') or Keyword('SPEED_Z')
Value = # assume I already have an expression valid for any value
Entry = Identifier + Literal('_') + Parameter + Value
tokens = Entry.parseString('ABC_123_SPEED_X 123')
#Error: pyparsing.ParseException: Expected "_" (at char 16), (line:1, col:17)

途中からアンダースコアを削除すると(そしてEntryそれに応じて定義を調整すると)、正しく解析されます。

_このパーサーを少し怠惰にして、キーワードに一致するまで待つにはどうすればよいですか (文字列全体を識別子として丸呑みし、存在しない を待つのではなく.

ありがとうございました。

[注: これは私の質問を完全に書き直したものです。私は本当の問題が何であるかを理解していませんでした]

4

4 に答える 4

7

あなたがやろうとしていることは、貪欲ではない一致を得ることなので、私はこれに基づいて答えました。これを pyparsing で実現するのは難しいようですが、巧妙さと妥協があれば不可能ではありません。以下はうまくいくようです:

from pyparsing import *
Parameter = Literal('SPEED_X') | Literal('SPEED_Y') | Literal('SPEED_Z')
UndParam = Suppress('_') + Parameter
Identifier = SkipTo(UndParam)
Value = Word(nums)
Entry = Identifier + UndParam + Value

これを対話型インタープリターから実行すると、次のことがわかります。

>>> Entry.parseString('ABC_123_SPEED_X 123')
(['ABC_123', 'SPEED_X', '123'], {})

これは妥協であることに注意してください。私は を使用SkipToしているため、時折アンダースコアが付いたIdentifier美しいだけでなく、邪悪で嫌な文字でいっぱいになる可能性があります。alphanums

編集:Identifier Paul McGuire のおかげで、次のように設定することで、本当にエレガントなソリューションを作成できます。

Identifier = Combine(Word(alphanums) +
        ZeroOrMore('_' + ~Parameter + Word(alphanums)))

これがどのように機能するかを調べてみましょう。まず、外側を無視しCombineます。これについては後で説明します。まず、参照文字列Word(alphanums)の一部を取得することがわかっています。この場合、「単語」にアンダースコアを含めることを許可していないことに注意してください。それを個別にロジックに組み込みます。'ABC''ABC_123_SPEED_X 123'

次に、'_123'吸い込まずにその部分をキャプチャする必要があり'_SPEED_X'ます。ZeroOrMoreこの時点でもスキップして、後で戻ってみましょう。アンダースコアを として開始しますがLiteral、 だけ'_'でショートカットできます。これにより、先頭のアンダースコアが得られますが、すべてではありません'_123'。本能的にWord(alphanums)、残りをキャプチャするために別の'_123_SPEED_X'. 代わりに、「アンダースコアの後に続くものが でない限り、Parameterそれを my の一部として解析します。これをIdentifierpyparse 用語で として記述し'_' + ~Parameter + Word(alphanums)ます。任意の数のアンダースコア + WordButNotParameter の繰り返しを使用できると想定しているため、それをラップします。式aZeroOrMore構築します。(イニシャルの後に少なくともアンダースコア + WordButNotParameter が常に必要な場合は、 を使用できますOneOrMore。)

最後に、最初の Word と特殊なアンダースコア + Word の繰り返しを一緒にラップして、それらが連続していて空白で区切られていないことを理解できるようにする必要があるため、式全体を構造でラップしCombineます。この方法で'ABC _123_SPEED_X'は解析エラーが発生しますが、'ABC_123_SPEED_X'正しく解析されます。

また、前者の方法は巧妙すぎてすぐに怒り出すので、変更Keywordしなければならなかったことにも注意してください。Literal私は s を信頼していませんKeyword。また、一致させることもできませんでした。

于 2009-12-15T07:46:51.887 に答える
1

識別子とパラメーターを1つのトークンとして解析し、それらを解析アクションで分割することもできます。

from pyparsing import *
import re

def split_ident_and_param(tokens):
    mo = re.match(r"^(.*?_.*?)_(.*?_.*?)$", tokens[0])
    return [mo.group(1), mo.group(2)]

ident_and_param = Word(alphanums + "_").setParseAction(split_ident_and_param)
value = Word(nums)
entry = ident_and_param + value

print entry.parseString("APC_123_SPEED_X 123")

上記の例では、識別子とパラメーターの形式が常にXXX_YYY(1つのアンダースコアを含む)であると想定しています。

そうでない場合は、split_ident_and_param()メソッドを調整する必要があります。

于 2009-12-15T10:31:12.373 に答える
1

識別子がアンダースコアで終わらないことが確実な場合は、定義でそれを強制できます。

from pyparsing import *

my_string = 'ABC_123_SPEED_X 123'

Identifier = Combine(Word(alphanums) + Literal('_') + Word(alphanums))
Parameter = Literal('SPEED_X') | Literal('SPEED_Y') | Literal('SPEED_Z')
Value = Word(nums)
Entry = Identifier + Literal('_').suppress() + Parameter  + Value
tokens = Entry.parseString(my_string)

print tokens # prints: ['ABC_123', 'SPEED_X', '123']

そうでない場合でも、識別子の長さが固定されている場合は、次のように識別子を定義できます。

Identifier = Word( alphanums + '_' , exact=7)
于 2009-12-15T09:55:02.577 に答える
-1

これは、おそらくあなたも自問したことがある質問への回答です:「実際のアプリケーションとはreduce何ですか?):

>>> keys = ['CAT', 'DOG', 'HORSE', 'DEER', 'RHINOCEROS']
>>> p = reduce(lambda x, y: x | y, [Keyword(x) for x in keys])
>>> p
{{{{"CAT" | "DOG"} | "HORSE"} | "DEER"} | "RHINOCEROS"}

編集:

これは、元の質問に対するかなり良い答えでした。私は新しいものに取り組む必要があります。

さらに編集:

あなたがやろうとしていることができないと確信しています。作成するパーサーpyparsingは先読みを行いません。したがって、 matchWord(alphanums + '_')を指定すると、文字、数字、またはアンダースコア以外の文字が見つかるまで文字の照合が続けられます。

于 2009-12-15T06:31:42.813 に答える