我正在尝试解析网络设备配置文件,虽然我会浏览整个文件,但我不想包含文件的所有条款,而只想包含其中的一个子集。
所以假设配置文件如下:
bootfile abc.bin
motd "this is a
message for everyone to follow"
.
.
.
group 1
group 2
.
.
.
permit tcp ab.b.c.d b.b.b.y eq 222
permit tcp ab.b.c.d b.b.b.y eq 222
permit tcp ab.b.c.d b.b.b.y eq 222
.
.
.
interface a
description this is interface a
vlan 33
interface b
description craigs list
no shut
vlan 33
no ip address
.
.
.
我只是想捕获接口线(按原样)以及描述和 VLAN 线 - 其他所有内容都将被忽略。界面内的内容将分为 2 个属性:有效和无效
所以语法看起来像这样:
Config[noskipsp]:
interfaces *= !InterfaceDefinition | InterfaceDefinition
;
InterfaceDefinition:
interface = intf
valids *= valid
invalids *= invalid
;
intf: /^interface .*\n/;
cmds: /^ (description|vlan) .*\n/;
invalid: /^(?!(interface|description|vlan) .*\n;
目标是获得一个Python接口数组,其中每个接口都有2个属性:valids和invalids,每个都是数组。有效数组将包含描述或 VLAN 条目,无效数组将包含其他所有内容。
有几个我似乎无法解决的挑战: 1-如何忽略所有其他不是接口定义的内容? 2- 如何确保所有接口最终都作为一个接口而不是另一个接口的 invalids 属性?
不幸的是 - 解析文本时的语法不会失败,但我对解析器如何遍历文本的理解似乎有问题,因为它在尝试读取通过“interface .*”部分的任何文本时会抱怨。
此外,目前我正在使用仅包含接口定义的文件进行显式测试,但目标是处理完整文件,仅针对接口,因此需要从语法方面丢弃所有其他内容。
你所做的通常被称为Island Grammars。您可以在 textX 中轻松做到这一点,并且可以轻松提取界面的实际结构。这是一种可能的解决方案:
from textx import metamodel_from_str
mmstr = r'''
Config:
(
/(?s)((?!interface).)*/ // <- consume everything till the keyword 'interface'
interfaces=Interface
)*
/(?s).*/ // <- consume all content after the last interface
;
Interface:
'interface' name=ID
'description' description=/[^\n]*/
/((?!vlan).)*/ // <- consume everything till the 'vlan'
'vlan' vlan=INT;
'''
model_str = r'''
bootfile abc.bin
motd "this is a
message for everyone to follow"
.
.
.
group 1
group 2
.
.
.
permit tcp ab.b.c.d b.b.b.y eq 222
permit tcp ab.b.c.d b.b.b.y eq 222
permit tcp ab.b.c.d b.b.b.y eq 222
.
.
.
interface a
description this is interface a
vlan 33
interface b
description craigs list
no shut
vlan 33
no ip address
'''
mm = metamodel_from_str(mmstr)
model = mm.model_from_str(model_str)
for i in model.interfaces:
print(i.name, i.description, i.vlan)
您始终可以将 textX 置于调试模式(通过传递
debug=True
)来查看解析过程并验证您的假设。