2016-12-30 105 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