2013-05-18 56 views
1

我很新pyparsing用戶和有缺失的比賽我不明白:pyparsing多條線路可選丟失的數據集

這是我想的文本解析:

polraw=""" 
set policy id 800 from "Untrust" to "Trust" "IP_10.124.10.6" "MIP(10.0.2.175)" "TCP_1002" permit 
set policy id 800 
set dst-address "MIP(10.0.2.188)" 
set service "TCP_1002-1005" 
set log session-init 
exit 
set policy id 724 from "Trust" to "Untrust" "IP_10.16.14.28" "IP_10.24.10.6" "TCP_1002" permit 
set policy id 724 
set src-address "IP_10.162.14.38" 
set dst-address "IP_10.3.28.38" 
set service "TCP_1002-1005" 
set log session-init 
exit 
set policy id 233 name "THE NAME is 527 ;" from "Untrust" to "Trust" "IP_10.24.108.6" "MIP(10.0.2.149)" "TCP_1002" permit 
set policy id 233 
set service "TCP_1002-1005" 
set service "TCP_1006-1008" 
set service "TCP_1786" 
set log session-init 
exit 

""" 

我設置語法這種方式:

KPOL = Suppress(Keyword('set policy id')) 
NUM = Regex(r'\d+') 
KSVC = Suppress(Keyword('set service')) 
KSRC = Suppress(Keyword('set src-address')) 
KDST = Suppress(Keyword('set dst-address')) 
SVC = dblQuotedString.setParseAction(lambda t: t[0].replace('"','')) 
ADDR = dblQuotedString.setParseAction(lambda t: t[0].replace('"','')) 
EXIT = Suppress(Keyword('exit')) 
EOL = LineEnd().suppress() 

P_SVC = KSVC + SVC + EOL 
P_SRC = KSRC + ADDR + EOL 
P_DST = KDST + ADDR + EOL 

x = KPOL + NUM('PId') + EOL + Optional(ZeroOrMore(P_SVC)) + Optional(ZeroOrMore(P_SRC)) + Optional(ZeroOrMore(P_DST)) 

for z in x.searchString(polraw): 
    print z 

結果集是如

['800', 'MIP(10.0.2.188)'] 
['724', 'IP_10.162.14.38', 'IP_10.3.28.38'] 
['233', 'TCP_1002-1005', 'TCP_1006-1008', 'TCP_1786'] 

800缺少服務標籤?

這裏有什麼問題。

由於通過提前 洛朗

回答

2

你所看到的問題是,在你的表達,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) 

現在解析器將乾淨處理額外的空格(甚至評論! )在表達式中的各個關鍵字之間。

+0

非常感謝Paul,提供的所有信息都闡明瞭我的想法,簡化了代碼並使其更具可讀性。祝你有個美好的一天! – user2396819