2016-01-20 81 views
-5

創建字典的字典我有一個包含這些行一個配置文件:需要邏輯讀取輸入文件

router1 = { 
    hostname: abcd 
     interfaces:{ 
      interface: gigabit 0/1 
      valn: 100 
      name: vlan1 
      ip_address: 1.1.1.1 
     } 
    clear: clear config all   
    } 

我的腳本應該從配置文件中讀取和創建詞典的詞典相同的格式。基於這本字典,我可以繼續進行自動化。

+1

您正在粘貼相同的文字兩次。 –

+0

我需要以相同的格式創建字典 –

+1

我不明白你在找什麼。我在第一段代碼和第二段代碼中看到了相同的內容。 –

回答

0

我不確定你爲什麼要這樣做,但我可以建議JSON嗎?

試試這個,你的文件(字典)保存爲一個有效的以.json文件,並在巨蟒只是這樣做

import json 
with open("filename.json",'r') as f: 
    data=json.load(f) 
print(data) 

數據變量應該有存儲相同的數據結構。如果你想要像保存對象更復雜的東西,嘗試泡菜

https://docs.python.org/3/library/pickle.html

+1

這種方法存在問題,OP的輸入不是有效的JSON文檔。 – vaultah

+0

使用上面的代碼後,我收到以下錯誤:ValueError:沒有JSON對象可以解碼 –

+0

@vaultah我認爲OP只想從磁盤存儲和檢索他的數據。他無法用更好的詞彙來表達。也許我錯了。 OP:如果您真的想嘗試這種方法,請閱讀JSON,因爲如果您想使用它,您需要創建一個有效的JSON文件。 – ishaan

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" 
    } 
} 
0

這pyparsing代碼將你的config條目解析成一個映射,你可以用這樣一個字典或對象:

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 

請注意,作爲解析過程的一部分,這些有效浮點數或整數值將已經從字符串轉換而來。