2016-12-30 91 views
1

我有此JSON文件:打印所有端口值

{ "data": [ { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test1", "{#PROC_ARGS}": "-l -c -g -k /etc/test1.conf", "{#PROC_PORT_1111}": "1111", "{#PROC_CONF}": "/etc/test1.conf" }, { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test2", "{#PROC_ARGS}": "-l -c -g -k /etc/test2.conf", "{#PROC_PORT_2222}": "2222", "{#PROC_PORT_3333}": "3333", "{#PROC_CONF}": "/etc/test2.conf" }, { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test3", "{#PROC_ARGS}": "-l -c -g -k /etc/test3.conf", "{#PROC_PORT_4444}": "4444", "{#PROC_CONF}": "/etc/test3.conf" } ]} 

這個文件是由這個python腳本閱讀:

import json 
import re 
import sys 
import unittest 
import StringIO 

def TestPorts(discoveryJson, spJson): 
    jsn = json.load(discoveryJson) 
    for dt in jsn['data']: 
     try: 
      id = dt['{#PROC_IDENT}'] 
      port = dt['{#PROC_PORT_1111}'] 
      spJson['data'].append({'{ID}': id, '{#PORT_1111}': port}) 
     except Exception as err: 
      pass 

def printTestPort(discFilespec, dumpDest=sys.stdout): 
    portJson = {'data': []} 
    try: 
     with open(discFilespec) as discJson: 
      TestPorts(discJson, portJson) 
    except: 
     pass 
    json.dump(portJson, dumpDest) 

if __name__ == '__main__': 
    printTestPort('/tmp/file.json') 

此刻,我只能打印只有一個端口值和id輸出值:

{ 
    "data": [ 
     { 
      "{#ID}": "test1", 
      "{#PORT_1111}": "1111" 
     } 
    ] 
} 

如何獲得下一個輸出? :

{ 
     "data": [ 
      { 
       "{#ID}": "test1", 
       "{#PORT_1111}": "1111" 
      }, 
      { 
       "{#ID}": "test2", 
       "{#PORT_2222}": "2222", 
       "{#PORT_3333}": "3333" 
      }, 
      { 
       "{#ID}": "test3", 
       "{#PORT_4444}": "4444" 
      } 
     ] 
    } 

請問您能幫助實現嗎?


讓我再澄清一次。

此JSON文件可以是可改變朝端口值:

{ "data": [ { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test1", "{#PROC_ARGS}": "-l -c -g -k /etc/test1.conf", "{#PROC_PORT_1111}": "1111", "{#PROC_CONF}": "/etc/test1.conf" }, { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test2", "{#PROC_ARGS}": "-l -c -g -k /etc/test2.conf", "{#PROC_PORT_2222}": "2222", "{#PROC_PORT_3333}": "3333", "{#PROC_CONF}": "/etc/test2.conf" }, { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test3", "{#PROC_ARGS}": "-l -c -g -k /etc/test3.conf", "{#PROC_PORT_4444}": "4444", "{#PROC_CONF}": "/etc/test3.conf" } ]} 

所以流程實例中的每個可能具有不同量的具有不同值的端口。例如test1可能有1237 7000和1234端口值,test2只有9004等等。

在我的Python代碼中,我能夠實現只讀取端口值之一,但我不知道如何實現,以便它打印每個進程ID的所有端口值。

例如:

{ 
     "data": [ 
      { 
       "{#ID}": "test1", 
       "{#PORT_1205}": "1205" 
      }, 
      { 
       "{#ID}": "test2", 
       "{#PORT_442}": "442", 
       "{#PORT_2004}": "2004" 
      }, 
      { 
       "{#ID}": "test3", 
       "{#PORT_4444}": "9001" 
      } 
     ] 
    } 

那麼端口值會自動更改JSON文件的修改情況。希望這次我更清楚地解釋。

+0

如果一個進程有多個端口,它們會在json數據中依次顯示*嗎? – wwii

+0

@ user54,結帳我的答案,因爲它顯然符合您的標準 – penta

回答

1

您的原始代碼拋出一個KeyError異常時的關鍵'{#PROC_PORT_1111}'不在場,所以你不能捕獲其他端口。這裏有一種方法 - 迭代項目;檢查你是否對該項目感興趣;按摩它;保存在一個新的容器中。

#setup 
import json, io 
from pprint import pprint 
s = """{ "data": [ { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test1", "{#PROC_ARGS}": "-l -c -g -k /etc/test1.conf", "{#PROC_PORT_1111}": "1111", "{#PROC_CONF}": "/etc/test1.conf" }, { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test2", "{#PROC_ARGS}": "-l -c -g -k /etc/test2.conf", "{#PROC_PORT_2222}": "2222", "{#PROC_PORT_3333}": "3333", "{#PROC_CONF}": "/etc/test2.conf" }, { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test3", "{#PROC_ARGS}": "-l -c -g -k /etc/test3.conf", "{#PROC_PORT_4444}": "4444", "{#PROC_CONF}": "/etc/test3.conf" } ]}""" 
f = io.StringIO(s) 

j = json.load(f) 
new_j = {'data' : []} 
for d in j['data']: 
    new_d = {} 
    new_d['{#ID}'] = d['{#PROC_IDENT}'] 
    for k, v in d.items(): 
     if k.startswith('{#PROC_PORT'): 
      k = k.replace('PROC_', '') 
      new_d[k] = v 
    new_j['data'].append(new_d) 


>>> pprint(new_j) 

{'data': [{'{#ID}': 'test1', '{#PORT_1111}': '1111'}, 
      {'{#ID}': 'test2', '{#PORT_2222}': '2222', '{#PORT_3333}': '3333'}, 
      {'{#ID}': 'test3', '{#PORT_4444}': '4444'}]} 
>>> 

使用正則表達式。我使用的是regex module,因爲它節省這是需要過程具有多個端口

import json 
import regex 
from pprint import pprint 

pattern = r'{.*?(?P<id>"{#PROC_IDENT}"[^,]+).*?((?P<ports>"{#PROC_PORT_\d+}"[^,]+),\s?)+' 
r = regex.compile(pattern) 
# formatting string 
new_json = """{{ "data": [{} ]}}""" 
items = [] 

s = """{ "data": [ { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test1", "{#PROC_ARGS}": "-l -c -g -k /etc/test1.conf", "{#PROC_PORT_1111}": "1111", "{#PROC_CONF}": "/etc/test1.conf" }, { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test2", "{#PROC_ARGS}": "-l -c -g -k /etc/test2.conf", "{#PROC_PORT_2222}": "2222", "{#PROC_PORT_3333}": "3333", "{#PROC_CONF}": "/etc/test2.conf" }, { "{#PROC}": "/usr/local/test", "{#PROC_IDENT}": "test3", "{#PROC_ARGS}": "-l -c -g -k /etc/test3.conf", "{#PROC_PORT_4444}": "4444", "{#PROC_CONF}": "/etc/test3.conf" } ]}""" 
f = io.StringIO(s) 
data = f.read() 

#with open('s.txt') as f: 
# data = f.read() 

for m in r.finditer(data): 
    d = m.capturesdict() 
    d['id'][0] = d['id'][0].replace('PROC_IDENT', 'ID') 
    d['ports'] = [port.replace('PROC_', '') for port in d['ports']] 
    s = ','.join(thing for v in d.values() for thing in v) 
    items.append('{{{}}}'.format(s)) 

new_json = new_json.format(', '.join(items)) 
j = json.loads(new_json) 


>>> pprint(j) 
{'data': [{'{#ID}': 'test1', '{#PORT_1111}': '1111'}, 
      {'{#ID}': 'test2', '{#PORT_2222}': '2222', '{#PORT_3333}': '3333'}, 
      {'{#ID}': 'test3', '{#PORT_4444}': '4444'}]} 
>>> 
+0

我在任何地方都能得到空值:('{#PROC_PORT_1111}'只是一個打印端口1111的試用版。但我需要以某種方式在命令腳本中自動確定'{#PROC_PORT_PORT_NUMBER_HERE}',例如,如果我們有2025端口和1701 proc test1 - 它會「{#ID}」:「test1」,「{#PORT_2025}」:「2025」,「{#PORT_1701}」:「1701」。對於剩下的pocess_ids,就像上次輸出中顯示的那樣我的請求。端口可能是完全不同的,它們的數量也可能不同。 – user54

+0

@ user54 - 我不理解你的評論。我已經編輯了答案 - 看看你是否在這之後。真正代表實際的數據嗎? - 如果沒有,請提供你問題中實際json數據的一小部分。 – wwii

+0

@ user54你正在使用哪種Python版本? – wwii

1

你需要,以便使其到達每個迭代的下一個端口(222233334444等)來更新您的循環中{#PROC_PORT_1111}關鍵。我已經添加了一個incr變量來跟蹤這個變量。每當你訪問該詞典還可以編輯功能使用get:如果你把except分支print聲明

def TestPorts(discoveryJson, spJson): 
    jsn = json.load(discoveryJson) 
    incr = 1111; 
    for dt in jsn.get('data'): 
     try: 
      id = dt.get('{#PROC_IDENT}') 
      port = dt.get('{#PROC_PORT_' + str(incr) + '}') 
      spJson.get('data').append({'{ID}': id, '{#PORT_' + str(incr) + '}': port}) 
      incr += incr; 
     except Exception as err: 
      pass 

,你會發現,你的執行將達到一個分支,兩次因KeyError。使用get而不是[]通常是一種更好的做法,因爲前者從不拋出KeyError,而後者不會。

資源:dict.get

+0

對不起,但它不起作用。它爲#PROC_PORT打印出空值,我不僅需要PROC_PORT_1111。我還需要其他端口,如最後一個json輸出中所示。 – user54

+0

我編輯了我的答案以提供正確的解決方案。問題在於你總是在循環的每次迭代中獲得#PROC_PORT_1111的值,而不是將其遞增到2222,3333等。 –

+0

感謝您的努力,但不幸的是,只要端口值可能是不同。例如:89,2001等。因此,如果出現這種變化 - 只要每次需要糾正,代碼都不會動態。 – user54

1

據我所知重複捕捉,我明白你的領域"{#PROC_PORT_2222}"變化與數字,即"{#PROC_PORT_XXXX}"所以在這我們需要使用正則表達式來匹配任何字符串,其中"{#PROC_PORT_}"爲固定字符串

import re 
import json 

with open('s.txt') as data_file: 
    data = json.load(data_file) 

k = data['data'] 
regex = r"{#PROC_PORT_[0-9]{4}}" 

test_str = str(k) 
lst=[] 
matches = re.finditer(regex, test_str) 
for matchNum, match in enumerate(matches): 
    matchNum = matchNum + 1 
    lst.append("{match}".format(match=match.group())) 


for b in k: 
    for a in lst: 
     try: 
      print b[str(a)] 
     except: 
      pass 

其中s.txt是具有json的txt文件。

這給出了輸出。

1111 
3333 
2222 
4444 

P.S.如果你的意思是關鍵的名字只是PORT不PROC_PORT,然後通過 regex = r"{#PORT_[0-9]{4}}"

PPS更換線

regex = r"{#PROC_PORT_[0-9]{4}}" 

我認爲這將改變數字將是4位數,如果沒有,那麼請在下面評論

+0

您的解決方案*構建* OP預期結果? – wwii

+0

是的,它會自己嘗試:-) – penta

+0

@wwii誰是OP? – penta