我正在使用https://github.com/igordejanovic/textX来解析dhcpd.conf
文件(不,https://pypi.org/project/iscconf/对我不起作用,它在我的dhcpd.conf
文件上崩溃),特别是使用以下命令提取主机固定地址。
记录如下:
host example1 {
option host-name "example1";
ddns-hostname "example1";
fixed-address 192.168.1.181;
}
host example2 {
hardware ethernet aa:bb:ff:20:fa:13;
fixed-address 192.168.1.191;
option host-name "example2";
ddns-hostname "example2";
}
代码:
def get_hosts(s):
grammar = """
config: hosts*=host ;
host: 'host' hostname=ID '{'
(
('hardware ethernet' hardware_ethernet=/[0-9a-fA-F:]+/';')?
'fixed-address' fixed_address=/([0-9]{1,3}\.){3}[0-9]{1,3}/';'
('option host-name' option_host_name=STRING';')?
('ddns-hostname' ddns_hostname=STRING';')?
)#
'}'
;
"""
mm = metamodel_from_str(grammar)
model = mm.model_from_str(s)
for host in model.hosts:
print host.hostname, host.fixed_address
现在,我无法使用此语法来解析整个dhcpd.conf
(显然,由于文件中还有很多其他元素无法使用语法,因此我会遇到语法错误);另一方面,我不想为此文件构造完整的语法,因为我只需要提取特定类型的主机记录即可。
我当然可以使用正则表达式提取主机记录并分别对其进行解析,但是我想知道是否有某种方法可以使textX
仅从文件中提取host
条记录,而忽略其余记录内容?
答案 0 :(得分:0)
textX作者在这里。我不是SO的常客:)。您可以进行正则表达式匹配和正则表达式前瞻,以消耗不需要的内容。这是一个完整的示例,即使存在关键字host
,也可以正确处理中间文本。如果前面没有单词config
,则规则host
首先会消耗一个字符,并且由于零个或多个运算符而导致重复。当我们得到一个单词host
时,我们尝试一次或多次匹配host
规则,并收集所有主机对象,如果该规则至少没有成功(请注意+=
的用法) ),我们使用单词host
,然后重复该过程。这可能可以做得更好(性能更高),但是您知道了。做这种事情时,很高兴知道默认情况下textX会使用空格,但是您可以使用noskipws
(请参阅the docs)将其全局或按规则关闭。
from textx import metamodel_from_str
def test_get_hosts():
grammar = r"""
config: ( /(?!host)./ | hosts+=host | 'host' )* ;
host: 'host' hostname=ID '{'
(
('hardware ethernet' hardware_ethernet=/[0-9a-fA-F:]+/';')?
'fixed-address' fixed_address=/([0-9]{1,3}\.){3}[0-9]{1,3}/';'
('option host-name' option_host_name=STRING';')?
('ddns-hostname' ddns_hostname=STRING';')?
)#
'}'
;
"""
conf_file = r"""
host example1 {
option host-name "example1";
ddns-hostname "example1";
fixed-address 192.168.1.181;
}
some arbitrary content in between
with word host but that fails to match host config.
host example2 {
hardware ethernet aa:bb:ff:20:fa:13;
fixed-address 192.168.1.191;
option host-name "example2";
ddns-hostname "example2";
}
"""
mm = metamodel_from_str(grammar)
model = mm.model_from_str(conf_file)
assert len(model.hosts) == 2
for host in model.hosts:
print(host.hostname, host.fixed_address)
if __name__ == "__main__":
test_get_hosts()
编辑:这是config
规则的另外两个建议:
一个简单的:
config: ( hosts+=host | /./ )* ;
(可能)一个性能更高的产品,在尝试host
之前,使用正则表达式引擎消耗的能量尽可能多:
config: ( /(?s:.*?(?=host))/ hosts*=host | 'host' )*
/(?s).*/;