需要帮助解析 Cisco 输出
Need help parsing Cisco output
我在尝试解析路由器的 mrib table 时遇到了一些问题。我已经能够解析其中的一些但有问题。例如我有以下输出:
(192.168.1.1,232.0.6.8) RPF nbr: 55.44.23.1 Flags: RPF
Up: 4w1d
Incoming Interface List
TenGigE0/0/0/1 Flags: A, Up: 4w1d
Outgoing Interface List
TenGigE0/0/0/10 Flags: A, Up: 4w1d
(192.168.55.3,232.0.10.69) RPF nbr: 66.76.44.130 Flags: RPF
Up: 4w1d
Incoming Interface List
TenGigE0/0/0/0 Flags: A, Up: 4w1d
TenGigE0/1/0/0 Flags: A, Up: 4w1d
TenGigE0/2/0/0 Flags: A, Up: 4w1d
Outgoing Interface List
TenGigE0/0/0/10 Flags: A, Up: 4w1d
TenGigE0/3/0/0 Flags: A, Up: 4w1d
TenGigE0/4/0/0 Flags: A, Up: 4w1d
我正在尝试用上面的输出构建一个数据结构。为了清楚起见,我希望它看起来像这样:
{'192.168.1.1,232.0.6.8': {'incoming': ['TenGigE0/0/0/1'],
'outgoing': ['TenGigE0/0/0/10']}}
以上听起来很简单。我遇到的主要问题之一是第二个街区。我正在尝试找出一种在传入和传出接口之后循环访问接口的方法。
不一定要求提供代码,但执行此类操作的最佳方法是什么?
假设您的输入完整且格式正确:
matcher = re.compile(
r'\((?P<range>[^\)]+)\)|'
r'(?P<incoming>\s+Incoming Interface List)|'
r'(?P<outgoing>\s+Outgoing Interface List)|'
r'\s+(?P<interface>TenGigE0[^\s]+)'
)
with open('router_table.txt', 'r') as f:
routing_table = []
current_range = ''
direction = ''
for line in f:
match = matcher.search(line)
if match:
if match.group('interface'):
routing_table[-1][current_range][direction].append(match.group('interface'))
if match.group('range'):
current_range = match.group('range')
routing_table.append(
{
current_range: {
'incoming': [],
'outgoing': []
}
}
)
if match.group('incoming'):
direction = 'incoming'
if match.group('outgoing'):
direction = 'outgoing'
好吧,如果您能够在 Python
中使用较新的 regex module
,您可以定义子模式并使用以下方法:
- 在开头定义 IP 地址的子模式
- ...以及传入和传出接口
- 分别解析接口
- 参见 a demo on regex101.com。
定义子模式
为 Incoming
和 Outgoing Interface
字符串、IP adress
和结尾定义子模式。
(?(DEFINE)
(?<ips>[^()]+)
(?<incoming>Incoming\ Interface \ List)
(?<outgoing>Outgoing\ Interface \ List)
(?<end>^$|\Z)
)
将正则表达式放在一起
将 IP 部分锚定到行首,并使用 tempered greedy 令牌和 negative lookaheads 用于 incoming/outgoing部分。
^\((?P<ip>(?&ips))\)
(?:(?!(?&incoming))[\s\S]+?)
(?&incoming)[\r\n]
(?P<in>(?!(?&outgoing))[\s\S]+?) # tempered greedy token
(?&outgoing)[\r\n]
(?P<out>(?!^$)[\s\S]+?)
(?&end)
解析 incoming/outgoing 部分
因为你只需要接口types/names,你可以简单地想出:
TenGig\S+ # TenGig, followed by anything NOT a whitespace
提示
你真的不需要定义子模式,但你需要自己重复很多次(因为 neg.lookaheads)。所以如果你需要坚持使用原来的 re
模块,你也可以很好地使用它。
粘在一起
所有代码都粘在一起,这将是:
import regex as re
string = """
(192.168.1.1,232.0.6.8) RPF nbr: 55.44.23.1 Flags: RPF
Up: 4w1d
Incoming Interface List
TenGigE0/0/0/1 Flags: A, Up: 4w1d
Outgoing Interface List
TenGigE0/0/0/10 Flags: A, Up: 4w1d
(192.168.55.3,232.0.10.69) RPF nbr: 66.76.44.130 Flags: RPF
Up: 4w1d
Incoming Interface List
TenGigE0/0/0/0 Flags: A, Up: 4w1d
TenGigE0/1/0/0 Flags: A, Up: 4w1d
TenGigE0/2/0/0 Flags: A, Up: 4w1d
Outgoing Interface List
TenGigE0/0/0/10 Flags: A, Up: 4w1d
TenGigE0/3/0/0 Flags: A, Up: 4w1d
TenGigE0/4/0/0 Flags: A, Up: 4w1d
"""
rx = re.compile(r"""
(?(DEFINE)
(?<ips>[^()]+)
(?<incoming>Incoming\ Interface \ List)
(?<outgoing>Outgoing\ Interface \ List)
(?<end>^$|\Z)
)
^\((?P<ip>(?&ips))\)
(?:(?!(?&incoming))[\s\S]+?)
(?&incoming)[\r\n]
(?P<in>(?!(?&outgoing))[\s\S]+?)
(?&outgoing)[\r\n]
(?P<out>(?!^$)[\s\S]+?)
(?&end)
""", re.MULTILINE|re.VERBOSE)
rxiface = re.compile(r'TenGig\S+')
result = dict()
for match in rx.finditer(string):
key = match.group('ip')
incoming = rxiface.findall(match.group('in'))
outgoing = rxiface.findall(match.group('out'))
result[key] = {'incoming': incoming, 'outgoing': outgoing}
print result
# {'192.168.1.1,232.0.6.8': {'outgoing': ['TenGigE0/0/0/10'], 'incoming': ['TenGigE0/0/0/1']}, '192.168.55.3,232.0.10.69': {'outgoing': ['TenGigE0/0/0/10', 'TenGigE0/3/0/0', 'TenGigE0/4/0/0'], 'incoming': ['TenGigE0/0/0/0', 'TenGigE0/1/0/0', 'TenGigE0/2/0/0']}}
我在尝试解析路由器的 mrib table 时遇到了一些问题。我已经能够解析其中的一些但有问题。例如我有以下输出:
(192.168.1.1,232.0.6.8) RPF nbr: 55.44.23.1 Flags: RPF
Up: 4w1d
Incoming Interface List
TenGigE0/0/0/1 Flags: A, Up: 4w1d
Outgoing Interface List
TenGigE0/0/0/10 Flags: A, Up: 4w1d
(192.168.55.3,232.0.10.69) RPF nbr: 66.76.44.130 Flags: RPF
Up: 4w1d
Incoming Interface List
TenGigE0/0/0/0 Flags: A, Up: 4w1d
TenGigE0/1/0/0 Flags: A, Up: 4w1d
TenGigE0/2/0/0 Flags: A, Up: 4w1d
Outgoing Interface List
TenGigE0/0/0/10 Flags: A, Up: 4w1d
TenGigE0/3/0/0 Flags: A, Up: 4w1d
TenGigE0/4/0/0 Flags: A, Up: 4w1d
我正在尝试用上面的输出构建一个数据结构。为了清楚起见,我希望它看起来像这样:
{'192.168.1.1,232.0.6.8': {'incoming': ['TenGigE0/0/0/1'],
'outgoing': ['TenGigE0/0/0/10']}}
以上听起来很简单。我遇到的主要问题之一是第二个街区。我正在尝试找出一种在传入和传出接口之后循环访问接口的方法。
不一定要求提供代码,但执行此类操作的最佳方法是什么?
假设您的输入完整且格式正确:
matcher = re.compile(
r'\((?P<range>[^\)]+)\)|'
r'(?P<incoming>\s+Incoming Interface List)|'
r'(?P<outgoing>\s+Outgoing Interface List)|'
r'\s+(?P<interface>TenGigE0[^\s]+)'
)
with open('router_table.txt', 'r') as f:
routing_table = []
current_range = ''
direction = ''
for line in f:
match = matcher.search(line)
if match:
if match.group('interface'):
routing_table[-1][current_range][direction].append(match.group('interface'))
if match.group('range'):
current_range = match.group('range')
routing_table.append(
{
current_range: {
'incoming': [],
'outgoing': []
}
}
)
if match.group('incoming'):
direction = 'incoming'
if match.group('outgoing'):
direction = 'outgoing'
好吧,如果您能够在 Python
中使用较新的 regex module
,您可以定义子模式并使用以下方法:
- 在开头定义 IP 地址的子模式
- ...以及传入和传出接口
- 分别解析接口
- 参见 a demo on regex101.com。
定义子模式
为 Incoming
和 Outgoing Interface
字符串、IP adress
和结尾定义子模式。
(?(DEFINE)
(?<ips>[^()]+)
(?<incoming>Incoming\ Interface \ List)
(?<outgoing>Outgoing\ Interface \ List)
(?<end>^$|\Z)
)
将正则表达式放在一起
将 IP 部分锚定到行首,并使用 tempered greedy 令牌和 negative lookaheads 用于 incoming/outgoing部分。
^\((?P<ip>(?&ips))\)
(?:(?!(?&incoming))[\s\S]+?)
(?&incoming)[\r\n]
(?P<in>(?!(?&outgoing))[\s\S]+?) # tempered greedy token
(?&outgoing)[\r\n]
(?P<out>(?!^$)[\s\S]+?)
(?&end)
解析 incoming/outgoing 部分
因为你只需要接口types/names,你可以简单地想出:
TenGig\S+ # TenGig, followed by anything NOT a whitespace
提示
你真的不需要定义子模式,但你需要自己重复很多次(因为 neg.lookaheads)。所以如果你需要坚持使用原来的 re
模块,你也可以很好地使用它。
粘在一起
所有代码都粘在一起,这将是:
import regex as re
string = """
(192.168.1.1,232.0.6.8) RPF nbr: 55.44.23.1 Flags: RPF
Up: 4w1d
Incoming Interface List
TenGigE0/0/0/1 Flags: A, Up: 4w1d
Outgoing Interface List
TenGigE0/0/0/10 Flags: A, Up: 4w1d
(192.168.55.3,232.0.10.69) RPF nbr: 66.76.44.130 Flags: RPF
Up: 4w1d
Incoming Interface List
TenGigE0/0/0/0 Flags: A, Up: 4w1d
TenGigE0/1/0/0 Flags: A, Up: 4w1d
TenGigE0/2/0/0 Flags: A, Up: 4w1d
Outgoing Interface List
TenGigE0/0/0/10 Flags: A, Up: 4w1d
TenGigE0/3/0/0 Flags: A, Up: 4w1d
TenGigE0/4/0/0 Flags: A, Up: 4w1d
"""
rx = re.compile(r"""
(?(DEFINE)
(?<ips>[^()]+)
(?<incoming>Incoming\ Interface \ List)
(?<outgoing>Outgoing\ Interface \ List)
(?<end>^$|\Z)
)
^\((?P<ip>(?&ips))\)
(?:(?!(?&incoming))[\s\S]+?)
(?&incoming)[\r\n]
(?P<in>(?!(?&outgoing))[\s\S]+?)
(?&outgoing)[\r\n]
(?P<out>(?!^$)[\s\S]+?)
(?&end)
""", re.MULTILINE|re.VERBOSE)
rxiface = re.compile(r'TenGig\S+')
result = dict()
for match in rx.finditer(string):
key = match.group('ip')
incoming = rxiface.findall(match.group('in'))
outgoing = rxiface.findall(match.group('out'))
result[key] = {'incoming': incoming, 'outgoing': outgoing}
print result
# {'192.168.1.1,232.0.6.8': {'outgoing': ['TenGigE0/0/0/10'], 'incoming': ['TenGigE0/0/0/1']}, '192.168.55.3,232.0.10.69': {'outgoing': ['TenGigE0/0/0/10', 'TenGigE0/3/0/0', 'TenGigE0/4/0/0'], 'incoming': ['TenGigE0/0/0/0', 'TenGigE0/1/0/0', 'TenGigE0/2/0/0']}}