あなたがやろうとしていることは、貪欲ではない一致を得ることなので、私はこれに基づいて答えました。これを 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 の一部として解析します。これをIdentifier
pyparse 用語で として記述し'_' + ~Parameter + Word(alphanums)
ます。任意の数のアンダースコア + WordButNotParameter の繰り返しを使用できると想定しているため、それをラップします。式aZeroOrMore
構築します。(イニシャルの後に少なくともアンダースコア + WordButNotParameter が常に必要な場合は、 を使用できますOneOrMore
。)
最後に、最初の Word と特殊なアンダースコア + Word の繰り返しを一緒にラップして、それらが連続していて空白で区切られていないことを理解できるようにする必要があるため、式全体を構造でラップしCombine
ます。この方法で'ABC _123_SPEED_X'
は解析エラーが発生しますが、'ABC_123_SPEED_X'
正しく解析されます。
また、前者の方法は巧妙すぎてすぐに怒り出すので、変更Keyword
しなければならなかったことにも注意してください。Literal
私は s を信頼していませんKeyword
。また、一致させることもできませんでした。