我有一个包含以下行的配置文件:
router1 = {
hostname: abcd
interfaces:{
interface: gigabit 0/1
valn: 100
name: vlan1
ip_address: 1.1.1.1
}
clear: clear config all
}
我的脚本应该从配置文件中读取并以相同的格式创建字典字典。根据这本词典,我可以继续进行自动化。
答案 0 :(得分:2)
要解决您的问题,您需要parser。可以使用各种库在Python中进行解析,请参阅SO退伍军人Ned Batchelder的Python parsing tools以获取可用的列表。
但是,您的数据格式并不复杂,因此编写一个不依赖于任何第三方模块的简单解析器非常容易。要将数据分解为单个令牌(又名lexical analysis),我们可以使用标准shlex模块。
下面的代码实现了一个非常简单的递归式解析器。它被开发出来了在Python 2.6.6上进行了测试,但它应该在Python 3上正常运行。您可能希望通过将其放入类中来封装它。恕我直言,这可能不是真的必要,但我想这取决于你的实际用例。
此代码使用json
模块打印已解析的字典;这并不是绝对必要的,但它确实可以很容易地打印出嵌套的词典。
代码包含一些错误检查,但很容易被欺骗接受奇怪的数据,因此如果您不能保证输入数据始终正确,您可能希望增强错误检查。
#!/usr/bin/env python
''' Parse config file data; see below for example data format
See http://stackoverflow.com/q/34898816/4014959
Written by PM 2Ring 2016.01.21
'''
from __future__ import print_function
import shlex
import string
import json
data = '''
router1 = {
hostname: abcd
interfaces:{
interface: gigabit 0/1
valn: 100
name: vlan1
ip_address: 1.1.1.1
}
clear: clear config all
}
'''
#Set up a simple lexer. `data` must be a file-/stream-like object
# with read() and readline() methods, or a string
lex = shlex.shlex(data)
lex.wordchars = string.ascii_letters + string.digits + "./:_"
def t_is(ch):
''' verify that the next token is ch '''
token = next(lex)
if token != ch:
raise ValueError('Line %d: Expected %r got %r'
% (lex.lineno, ch, token))
def get_word():
''' get next token if it's a word.
Otherwise, push it back & return None
'''
token = next(lex)
if token not in '{}':
return token
lex.push_token(token)
def is_key(token):
return token[-1] == ':'
def get_value():
''' get value, which may be a list of words or a dict '''
token = next(lex)
if token == '{':
#Value is a dict
lex.push_token(token)
return get_dict()
#Value consists of one or more non-key words
value = [token]
while True:
token = get_word()
if token is None:
break
if is_key(token):
lex.push_token(token)
break
value.append(token)
return ' '.join(value)
def get_dict():
''' parse a dictionary '''
t_is('{')
d = {}
while True:
#get key, value pairs
key = get_word()
if key is None:
t_is('}')
return d
if not is_key(key):
raise ValueError('Line %d: Bad key %r'
% (lex.lineno, key))
d[key[:-1]] = get_value()
def get_cfg():
''' parse config data, returning the name and the dict '''
name = get_word()
if name is None:
raise ValueError('Line %d: Expected name, got %r'
% (lex.lineno, next(lex)))
t_is('=')
d = get_dict()
return name, d
#----------------------------------------------------------
print(data)
print(20 * '- ' + '\n')
#for token in lex: print(token)
name, cfg = get_cfg()
print(name)
print(json.dumps(cfg, indent=4, sort_keys=True))
输出
router1 = {
hostname: abcd
interfaces:{
interface: gigabit 0/1
valn: 100
name: vlan1
ip_address: 1.1.1.1
}
clear: clear config all
}
- - - - - - - - - - - - - - - - - - - -
router1
{
"clear": "clear config all",
"hostname": "abcd",
"interfaces": {
"interface": "gigabit 0/1",
"ip_address": "1.1.1.1",
"name": "vlan1",
"valn": "100"
}
}
答案 1 :(得分:0)
我不确定你为什么要这样做,但我可以建议使用JSON吗?
试试这个,将你的文档(字典)保存为有效的.json文件,然后在python中执行此操作
import json
with open("filename.json",'r') as f:
data=json.load(f)
print(data)
数据变量应具有与存储相同的数据结构。如果你想要更复杂的东西,如保存对象,请尝试pickle
答案 2 :(得分:0)
此pyparsing代码会将您的配置条目解析为您可以像dict或对象一样使用的映射:
from pyparsing import *
LBRACE,RBRACE,LBRACK,RBRACK,COLON,EQ = map(Suppress, "{}[]:=")
NL = LineEnd()
key = Word(alphas, alphanums+'_')
# forward declare value, since this will be a recursive definition
value = Forward()
key_value = Group(key + COLON + value)
# parse actions will do string->int and string->float conversions at parse time
integer = Regex(r'[+-]?\d+').setParseAction(lambda t: int(t[0]))
real = Regex(r'[+-]?\d+\.\d*').setParseAction(lambda t: float(t[0]))
string = restOfLine.setParseAction(lambda t: t[0].strip())
dictvalue = Group(LBRACE + Dict(ZeroOrMore(key_value)) + RBRACE)
listvalue = Group(LBRACK + Dict(ZeroOrMore(value)) + RBRACK)
# assign recursive contents to value using <<=
value <<= (real | integer) + FollowedBy(NL) | dictvalue | listvalue | string
setting = Group(key + EQ + value)
config_parser = Dict(OneOrMore(setting))
config = config_parser.parseString(data)
# dump out parsed contents
print config.dump()
# access parsed contents like a dict or an object
print config.keys()
print config.router1.keys()
print config.router1.hostname
打印:
[['router1', [['hostname', 'abcd '], ['interfaces', [['interface', ...
- router1: [['hostname', 'abcd '], ['interfaces', [['interface', ...
- clear: clear config all
- hostname: abcd
- interfaces: [['interface', 'gigabit 0/1 '], ['valn', 100], ...
- interface: gigabit 0/1
- ip_address: 1.1.1.1
- name: vlan1
- valn: 100
['router1']
['interfaces', 'hostname', 'clear']
abcd
请注意,作为解析过程的一部分,那些有效浮点数或整数的值将已从字符串转换。