我是一个非常新的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缺少服务标签???
这里有什么不对。
先谢谢 劳伦
答案 0 :(得分:3)
你看到的问题是,在你的表达式中,只有在跳过可选的SVC和SRC之后才会查找DST。你有几个选择,我会仔细阅读每个选项,这样你就可以了解这里发生了什么。
(但首先,编写“Optional(ZeroOrMore(anything))”没有意义 - ZeroOrMore已经暗示可选,所以我将在任何这些选择中删除Optional部分。)
如果要以任何顺序获得SVC,SRC和DST,您可以重构ZeroOrMore以接受三种数据类型中的任何一种,如下所示:
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*"))
注意每个名称上的尾部'*' - 这相当于调用setRllultsName并且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表达式上包装ungroup,可能是这样的:
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,但不能接受。 (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的类允许编写相同类型的东西:
Each([A,B,C,D])
意思是“必须以任何顺序分别拥有A,B,C和D中的一个”。和And,Or,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))
我看过在这个表达式中使用结果名称,而ZeroOrMore似乎让人感到困惑,可能仍然是如何做到这一点的错误。所以你可能不得不保留使用每个更基本的情况,比如我的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'))
有点脆弱,因为如果'set'和'policy'之间或'policy'和'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)
现在,您的解析器将在表达式中的各个关键字之间干净地处理额外的空格(甚至是注释!)。