Автор textX здесь. Я не частый посетитель ТАК :). Вы можете поиграть с регулярными выражениями и заглядывать в регулярные выражения, чтобы использовать нежелательный контент. Вот полный пример, который правильно обрабатывает промежуточный текст, даже если есть ключевое слово host
. Правило config
сначала использует символ, если впереди нет слова host
, и это повторяется из-за нуля или более оператора. Когда мы получаем слово host
, мы пытаемся выполнить правило host
правило один или несколько раз и собрать все объекты хоста, если правило не выполнено хотя бы один (обратите внимание на использование +=
), мы используем слово host
и повторите процесс. Это, вероятно, может быть сделано лучше (более производительным), но вы поняли идею. При выполнении такого рода вещей полезно знать, что textX по умолчанию использует пробелы, но вы можете отключить это либо глобально, либо по правилу, используя noskipws
(см. документы ).
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).*/;