python - 如何单独处理输入文件的块?
问题描述
我正在尝试读取防火墙配置并使用 Python 操作它定义的对象,然后更改对象名称并将其导出到新的配置文件。输入示例:
edit "host1"
set subnet 10.0.0.10 255.255.255.255
next
edit "host2"
set subnet 10.0.0.11 255.255.255.255
next
读取文件时,我需要一种方法来遍历“edit [...]”的每个实例,并设置以下属性(可以是多个)。本质上,包含“edit”的行表示新对象的开始,“next”表示该对象的结束。目标是检查每个对象的内容并根据它的内容重命名它,基于前面的示例,输出将是:
edit "10.0.0.10"
set subnet 10.0.0.10 255.255.255.255
next
edit "10.0.0.11"
set subnet 10.0.0.11 255.255.255.255
next
操作文本本身应该不是什么大问题,但我目前一直在寻找一种方法来单独处理配置的每个块。
我曾考虑将输入转换为 XML,然后使用 ElementTree,但我希望有一种更优雅的方式来完成它,而无需我因为缺乏编程经验而没有看到的额外步骤。
提前感谢您提供有关如何解决此问题的任何意见。
解决方案
递归下降解析器时间!
如果这些配置文件真的那么简单,你可以使用这个语法:
start: block*
block: EDIT HOSTNAME rule* NEXT
HOSTNAME: /"[^"]"/
rule: SET SUBNET IP IP
IP: /\d+\.\d+\.\d+\.\d+/
然后解析器看起来像这样。edit
它使用规则中的主机自动重写所有块set
。
import re
class Parser:
def __init__(self, tokens: list):
self.tokens = tokens
def _next(self) -> str:
token = self.tokens[0]
del self.tokens[0]
return token
def _peek(self) -> str:
return self.tokens[0]
def consume(self, value: str) -> str:
token = self._next()
if token == value:
return token
raise SyntaxError(f"Could not consume {value!r} given {token!r} + {self.tokens}")
def consume_regex(self, regex) -> str:
token = self._next()
match, = regex.fullmatch(token).groups()
return match
def parse(self):
edits = self.parse_start()
assert not self.tokens
return edits
def parse_start(self):
"start: edit*"
edits = []
while self.tokens:
edit = self.parse_edit()
edits.append(edit)
return edits
def parse_edit(self) -> str:
"edit: EDIT HOST rule NEXT"
HOST_REGEX = re.compile(r'^"([^"]*)"$')
_EDIT = self.consume('edit')
_HOST = self.consume_regex(HOST_REGEX)
_rule = self.parse_rule()
_NEXT = self.consume('next')
# REWRITE HERE!
rewritten = f'''
{_EDIT} "{_rule['IP']}"
{_rule['type']} {_rule['subnet']} {_rule['IP']} {_rule['mask']}
{_NEXT}
'''.strip()
return rewritten
def parse_rule(self) -> dict:
"rule: SET rule_set" # other rules can be added
tok = self._peek()
if tok == 'set':
return self.parse_rule_set()
raise SyntaxError(f'Unknown rule {tok!r}')
def parse_rule_set(self) -> dict:
"rule_set: SET SUBNET IP MASK"
# this regex doesn't check the validity of the IP address,
# but it's good enough here
IP_REGEX = re.compile(r"^(\d+\.\d+\.\d+\.\d+)$")
_SET = self.consume('set')
_SUBNET = self.consume('subnet')
_IP = self.consume_regex(IP_REGEX)
_MASK = self.consume_regex(IP_REGEX)
return {'type': 'set', 'subnet': _SUBNET, 'IP': _IP, 'mask': _MASK}
if __name__ == '__main__':
data = '''
edit "host1"
set subnet 10.0.0.10 255.255.255.255
next
edit "host2"
set subnet 10.0.0.11 255.255.255.255
next
'''
ret = Parser(data.split()).parse()
print('\n'.join(ret))
输出:
$ python3 test.py
edit "10.0.0.10"
set subnet 10.0.0.10 255.255.255.255
next
edit "10.0.0.11"
set subnet 10.0.0.11 255.255.255.255
next
$
推荐阅读
- arrays - 为什么我的一维直方图没有正确显示?
- bash - 如何在终端中创建自定义命令?
- php - 向特定用户隐藏页面
- mysql - 有没有办法告诉 MySQL 在 auto_increment 字段溢出时不要抛出?
- python-3.x - python3:csv.writer 如何删除行尾^M?
- c# - 使用特殊字符 %3C 重定向
- angularjs - 我在启动新部署的服务器时出错
- asp.net-core - .NET Core Web API、JWT 和 Swagger - 401 显示为未记录而不是未授权
- php - 使用 str_replace 自己的编码系统
- kframework - 无法计算最少种类的术语(其中术语是列表)