我根據this one得出的答案,因爲你要做的是得到一個非貪婪的匹配。看起來這很難在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
以下炮製一個真正優雅的解決方案:
Identifier = Combine(Word(alphanums) +
ZeroOrMore('_' + ~Parameter + Word(alphanums)))
讓我們檢查是如何工作的。首先,忽略外層Combine
;我們將在稍後討論。從Word(alphanums)
開始,我們知道我們將獲得參考字符串'ABC_123_SPEED_X 123'
的'ABC'
部分。請注意,在這種情況下,我們不允許「單詞」包含下劃線。我們將其分別構建到邏輯中。
接下來,我們需要捕獲'_123'
部分,而不吸取'_SPEED_X'
。我們現在也跳過ZeroOrMore
並稍後返回。我們以下劃線作爲Literal
開頭,但我們可以使用'_'
的快捷鍵,這將使我們獲得領先的下劃線,但不是全部的'_123'
。假如我們將另一個Word(alphanums)
捕獲其餘的,但這正是通過消耗所有剩餘的'_123_SPEED_X'
而使我們陷入麻煩的原因。相反,我們會說:「只要下劃線後面是而不是,Parameter
,就可以解析它,作爲我的Identifier
的一部分我們聲稱在pyparsing術語中爲'_' + ~Parameter + Word(alphanums)
因爲我們假設我們可以有任意數量的下劃線+ WordButNotParameter重複,我們總結認爲表達ZeroOrMore
結構。(如果你總是期望至少下劃線+ WordButNotParameter在最初,你可以使用OneOrMore
)。
最後,我們需要包裝最初的Word和特殊下劃線+字重複在一起,這樣就可以理解它們是連續的,而不是由空白分隔的,所以我們將整個表達式包裝在一個Combine
結構中。這樣'ABC _123_SPEED_X'
將引發一個解析錯誤,但'ABC_123_SPEED_X'
將正確解析。
還請注意,我不得不將Keyword
更改爲Literal
,因爲前者的方式太微妙和快速的憤怒。我不信任Keyword
,我也不能與他們匹配。
我知道這一點:你應該在'Parameter'的賦值中使用'|',而不是'''。 – 2009-12-15 06:56:40
這個問題的標題應該是「pyparsing中的非貪婪匹配」。 – gotgenes 2009-12-15 07:48:42
@gotgenes:完成。製作更清晰的標題。 – Escualo 2009-12-15 17:41:20