你所看到的問題是,在你的表達,DST的只是看了後已經跳過了可選的SVC的和SRC的。你有幾個選擇,我會通過每個選項,讓你可以瞭解到這裏所發生的一切。
(但首先,有書面不點「可選的(零或(任何))」 - 零或已經暗示可選,所以我會在任何這些選擇放棄可選部分)
如果你要得到SVC的,SRC的,和DST的任何順序,你可以重構你的零或接受任何三種數據類型的,像這樣的:
x = KPOL + NUM('PId') + EOL + ZeroOrMore(P_SVC|P_SRC|P_DST)
這將允許你混合使用不同類型的語句,並且它們將全部作爲ZeroOrMore重複的一部分收集。
如果你想保持這些不同類型的羣體發言的,那麼你可以一個結果的名字添加到每個:
x = KPOL + NUM('PId') + EOL + ZeroOrMore(P_SVC("svc*")|
P_SRC("src*")|
P_DST("dst*"))
注意每名尾隨「*」 - 這等同於調用setResultsName listAllMatches參數等於True。由於每個不同的表達式都匹配,不同類型的結果將被收集到「svc」,「src」或「dst」結果名稱中。調用z.dump()
將列出令牌和結果名稱及其值,以便您可以看到這是如何工作的。
set policy id 233
set service "TCP_1002-1005"
set dst-address "IP_10.3.28.38"
set service "TCP_1006-1008"
set service "TCP_1786"
set log session-init
exit
顯示此爲z.dump()
:
['233', 'TCP_1002-1005', 'IP_10.3.28.38', 'TCP_1006-1008', 'TCP_1786']
- PId: 233
- dst: [['IP_10.3.28.38']]
- svc: [['TCP_1002-1005'], ['TCP_1006-1008'], ['TCP_1786']]
如果換取消組合在P_xxx表情,也許是這樣的:
P_SVC,P_SRC,P_DST = (ungroup(expr) for expr in (P_SVC,P_SRC,P_DST))
則輸出更清潔的前瞻性:
['233', 'TCP_1002-1005', 'IP_10.3.28.38', 'TCP_1006-1008', 'TCP_1786']
- PId: 233
- dst: ['IP_10.3.28.38']
- svc: ['TCP_1002-1005', 'TCP_1006-1008', 'TCP_1786']
這實際上看起來不錯,但讓我傳一個選項。有很多情況下解析器必須以任何順序查找幾個子表達式。假設他們是A,B,C和D.爲了以任何順序接受這些信息,你可以寫一些類似於OneOrMore(A|B|C|D)
的東西,但是這可以接受多個A,或者A,B和C,但不是D.(A + B + C + D)|的徹底/耗盡組合爆炸(A + B + D + C)|等可以寫,或者你也許可以用類似
from itertools import permutations
mixNmatch = MatchFirst(And(p) for p in permutations((A,B,C,D),4))
自動執行它但在pyparsing稱爲每次類,允許寫這樣的事情:
Each([A,B,C,D])
意義「必須有A,B,C和D中的任意一個「。並且像And,或者NotAny等等,也有一個操作者的捷徑:
A & B & C & D
這意味着同樣的事情。
如果你想 「必須有A,B和C,以及可選d」,然後寫:
A & B & C & Optional(D)
,這將與同類行爲的分析,尋找A,B,C ,和D,而不管輸入的順序如何,以及D是最後一個還是與A,B和C混合。您還可以使用OneOrMore和ZeroOrMore來指示任何表達式的可選重複。
所以,你可以寫你的表達:
x = KPOL + NUM('PId') + EOL + (ZeroOrMore(P_SVC) &
ZeroOrMore(P_SRC) &
ZeroOrMore(P_DST))
我看着使用結果的名稱與此表達,以及零次或多次的似乎是令人困惑的事,也許仍然在如何做到這一點的錯誤。所以你可能必須預留使用每個更多的基本案例,如我的A,B,C,D例子。但我想讓你知道它。
你的解析器的一些其他注意事項:
dblQuotedString.setParseAction(lambda t: t[0].replace('"',''))
可能是更好的書面 dblQuotedString.setParseAction(removeQuotes)
。您的示例中沒有任何嵌入式引號,但瞭解您的假設可能無法轉化爲未來的應用程序,這很好。這裏有一對夫婦的去除定義的報價方式:
dblQuotedString.setParseAction(lambda t: t[0].replace('"',''))
print dblQuotedString.parseString(r'"This is an embedded quote \" and an ending quote \""')[0]
# prints 'This is an embedded quote \ and an ending quote \'
# removed leading and trailing "s, but also internal ones too, which are
# really part of the quoted string
dblQuotedString.setParseAction(lambda t: t[0].strip('"'))
print dblQuotedString.parseString(r'"This is an embedded quote \" and an ending quote \""')[0]
# prints 'This is an embedded quote \" and an ending quote \'
# removed leading and trailing "s, and leaves the one internal ones but strips off
# the escaped ending quote
dblQuotedString.setParseAction(removeQuotes)
print dblQuotedString.parseString(r'"This is an embedded quote \" and an ending quote \""')[0]
# prints 'This is an embedded quote \" and an ending quote \"'
# just removes leading and trailing " characters, leaves escaped "s in place
KPOL = Suppress(Keyword('set policy id'))
是有點脆弱,彷彿有「設置」和「政策」,或者在「政策」之間的任何多餘的空格會破'ID'。我通常先單獨定義的所有關鍵字定義這些類型的表達式:
SET,POLICY,ID,SERVICE,SRC_ADDRESS,DST_ADDRESS,EXIT = map(Keyword,
"set policy id service src-address dst-address exit".split())
,然後使用定義不同的表情:
KSVC = Suppress(SET + SERVICE)
KSRC = Suppress(SET + SRC_ADDRESS)
KDST = Suppress(SET + DST_ADDRESS)
現在解析器將乾淨處理額外的空格(甚至評論! )在表達式中的各個關鍵字之間。
非常感謝Paul,提供的所有信息都闡明瞭我的想法,簡化了代碼並使其更具可讀性。祝你有個美好的一天! – user2396819