解析网络接口配置的正则表达式
我在想下面这个问题是不是可以用一个普通的正则表达式来解决,还是说我应该用标准的循环逐行检查。
当我运行附带的代码时,我得到了 ['Ethernet0/22', 'Ethernet0/24']
,但我想要的结果应该是 ['Ethernet0/23', 'Ethernet0/25']
。
对此有什么建议吗?
import re
txt='''#
interface Ethernet0/22
stp disable
broadcast-suppression 5
mac-address max-mac-count 1
port access vlan 452
#
interface Ethernet0/23
stp disable
description BTO
broadcast-suppression 5
port access vlan 2421
#
interface Ethernet0/24
stp disable
description Avaya G700
broadcast-suppression 5
port access vlan 452
#
interface Ethernet0/25
stp disable
description BTO
broadcast-suppression 5
port access vlan 2421
#
'''
re1 = '''^interface (.*?$).*?BTO.*?^#$'''
rg = re.compile(re1,re.IGNORECASE|re.DOTALL|re.MULTILINE)
m = rg.findall(txt)
if m:
print m
4 个回答
2
一个不使用正则表达式的例子:
print [ stanza.split()[0]
for stanza in txt.split("interface ")
if stanza.lower().startswith( "ethernet" )
and stanza.lower().find("bto") > -1 ]
解释:
我发现从“内到外”阅读组合内容效果最好:
for stanza in txt.split("interface ")
把文本在每次出现“interface ”(包括后面的空格)的位置切分开。切分后得到的片段看起来像这样:
Ethernet0/22
stp disable
broadcast-suppression 5
mac-address max-mac-count 1
port access vlan 452
#
接下来,过滤这些片段:
if stanza.lower().startswith( "ethernet" ) and stanza.lower().find("bto") > -1
这个过程应该很容易理解。
stanza.split()[0]
把匹配到的片段按空格切分,然后把第一个元素放到结果列表里。这样做配合过滤器 startswith
可以避免出现 IndexError
错误。
5
这里有一个简单的pyparsing解析器,可以用来处理你的文件。这个解析器不仅能解决你眼前的问题,还能给你一组很方便的对象,让你轻松访问每个接口中的数据。
下面是这个解析器的代码:
from pyparsing import *
# set up the parser
comment = "#" + Optional(restOfLine)
keyname = Word(alphas,alphanums+'-')
value = Combine(empty + SkipTo(LineEnd() | comment))
INTERFACE = Keyword("interface")
interfaceDef = Group(INTERFACE + value("name") + \
Dict(OneOrMore(Group(~INTERFACE + keyname + value))))
# ignore comments (could be anywhere)
interfaceDef.ignore(comment)
# parse the source text
ifcdata = OneOrMore(interfaceDef).parseString(txt)
接下来,看看怎么使用它:
# use dump() to list all of the named fields created at parse time
for ifc in ifcdata:
print ifc.dump()
# first the answer to the OP's question
print [ifc.name for ifc in ifcdata if ifc.description == "BTO"]
# how to access fields that are not legal Python identifiers
print [(ifc.name,ifc['broadcast-suppression']) for ifc in ifcdata
if 'broadcast-suppression' in ifc]
# using names to index into a mapping with string interpolation
print ', '.join(["(%(name)s, '%(port)s')" % ifc for ifc in ifcdata ])
输出结果是:
['interface', 'Ethernet0/22', ['stp', 'disable'], ['broadcast-suppression', '5'], ['mac-address', 'max-mac-count 1'], ['port', 'access vlan 452']]
- broadcast-suppression: 5
- mac-address: max-mac-count 1
- name: Ethernet0/22
- port: access vlan 452
- stp: disable
['interface', 'Ethernet0/23', ['stp', 'disable'], ['description', 'BTO'], ['broadcast-suppression', '5'], ['port', 'access vlan 2421']]
- broadcast-suppression: 5
- description: BTO
- name: Ethernet0/23
- port: access vlan 2421
- stp: disable
['interface', 'Ethernet0/24', ['stp', 'disable'], ['description', 'Avaya G700'], ['broadcast-suppression', '5'], ['port', 'access vlan 452']]
- broadcast-suppression: 5
- description: Avaya G700
- name: Ethernet0/24
- port: access vlan 452
- stp: disable
['interface', 'Ethernet0/25', ['stp', 'disable'], ['description', 'BTO'], ['broadcast-suppression', '5'], ['port', 'access vlan 2421']]
- broadcast-suppression: 5
- description: BTO
- name: Ethernet0/25
- port: access vlan 2421
- stp: disable
['Ethernet0/23', 'Ethernet0/25']
[('Ethernet0/22', '5'), ('Ethernet0/23', '5'), ('Ethernet0/24', '5'), ('Ethernet0/25', '5')]
(Ethernet0/22, 'access vlan 452'), (Ethernet0/23, 'access vlan 2421'), (Ethernet0/24, 'access vlan 452'), (Ethernet0/25, 'access vlan 2421')
4
你的问题是正则表达式在下一个组中继续找到BTO。作为一个简单的解决办法,你可以在接口ID中禁止使用"#"这个字符(假设在记录中这个字符是不合法的,只是用来分隔它们)。
re1 = '''^interface ([^#]*?$)[^#]*?BTO.*?^#$'''