有些命令行可以返回json格式的输出,比如openstack的cli命令、iperf3,我们可以去除输出中前后和中间多余的内容, 提取出json字符串,转换成字典,方便后续操作其中的内容。 实现下面的函数完成这项工作。 不论命令是执行在物理服务器、虚拟机服务器、网络设备上,也不论是在ssh/telnet vty上执行, 还是console或者本地shell上执行,也不论是一条命令的输出,还是一组命令的输出, 只要输出中有json字符串,就可以将输出传入下面的函数中,得到字典。 这里所说的json字符串之外的多余的内容,可能是设备的prompt、输入的(其它)命令以及它们的输出。 其实,这个函数本身不在意输入的text是如何得来的,分析cli的输出只是一种使用场景。
源代码:
# python3.8
# coding=utf-8
# author=liuyifan
import json
"""
初步版本:只能提取文本中唯一的json字符串
从文本中提取出json字符串,首先去除前后多余的内容,然后将其转换成字典返回。
局限:文本中只能有一个json字符串,该json字符串前后的内容中不能有{和}。
说明:json字符串内部还有{和}不影响提取和解析。JSON字符串前后没有多余内容时也能正常提取和解析。
"""
def convert_json_in_text_to_dict(text):
# 去除{之前的多余内容,这条语句同时适用于{之前没有多余内容的情况
t = text[len(text.split("{")[0]) :]
suffix_length = len(text.split("}")[-1])
# 去除}之后的多余内容, }之后没有多余内容时,则不用处理
if suffix_length:
t = t[:-suffix_length]
# 转换成字典返回
return json.loads(t)
"""
进阶版本:能提取任意多个json字符串。
从文本中提取出所有json字符串,将它们转换成字典,最后返回字典组成的列表。
说明:输入的文本中可以有不属于任何json字符串的内容,
但是这些内容中不能有{和},否则可能影响json字符串的定界。
文本中可以有多个json字符串。
json字符串内部可以嵌套成对的{}。但是不能有不成对的{或者}。
实现说明:这里用栈的来匹配左右花括号,从而定界每一个json字符串。
按index遍历输入的文本,每到遇到{,则将其index入栈,每当遇到},则弹出栈内的一个{,
如果弹出后栈为空了,说明到了一个json字符串的结尾。
而刚刚弹出的元素值就是这个json字符串的开始位置。
"""
def convert_all_json_in_text_to_dict(text):
dicts, stack = [], []
for i in range(len(text)):
if text[i] == "{":
stack.append(i)
elif text[i] == "}":
begin = stack.pop()
if not stack:
dicts.append(json.loads(text[begin : i + 1]))
return dicts
# 看一下执行效果
text1 = """
ab: cd
{
"network": {
"name": "net101",
"admin_state_up": true,
"segments": [
{
"provider:segmentation_id": 5,
"provider:physical_network": "public",
"provider:network_type": "vlan"
},
{
"provider:physical_network": "default",
"provider:network_type": "flat"
}
]
}
}
ef> gh
"""
import pprint
d = convert_json_in_text_to_dict(text1)
print(type(d))
pprint.pprint(d)
pprint.pprint(d["network"]["segments"])
text2 = """
ab: cd
{
"network": {
"name": "net101",
"admin_state_up": true,
"segments": [
{
"provider:segmentation_id": 5,
"provider:physical_network": "public",
"provider:network_type": "vlan"
},
{
"provider:physical_network": "default",
"provider:network_type": "flat"
}
]
}
}
ef> gh
{
"students": [
{ "name":"Tom" , "age":18 },
{ "name":"Lily" , "age":19 }
]
}
HIJK#
"""
ds = convert_all_json_in_text_to_dict(text2)
print(
"---------------------------convert_all_json_in_text_to_dict()的输出----------------------------------------------"
)
pprint.pprint(ds)
print(type(ds[0]))
pprint.pprint(ds[0])
pprint.pprint(ds[0]["network"]["segments"])
pprint.pprint(ds[1])
输出:
<class 'dict'>
{'network': {'admin_state_up': True,
'name': 'net101',
'segments': [{'provider:network_type': 'vlan',
'provider:physical_network': 'public',
'provider:segmentation_id': 5},
{'provider:network_type': 'flat',
'provider:physical_network': 'default'}]}}
[{'provider:network_type': 'vlan',
'provider:physical_network': 'public',
'provider:segmentation_id': 5},
{'provider:network_type': 'flat', 'provider:physical_network': 'default'}]
---------------------------convert_all_json_in_text_to_dict()的输出----------------------------------------------
[{'network': {'admin_state_up': True,
'name': 'net101',
'segments': [{'provider:network_type': 'vlan',
'provider:physical_network': 'public',
'provider:segmentation_id': 5},
{'provider:network_type': 'flat',
'provider:physical_network': 'default'}]}},
{'students': [{'age': 18, 'name': 'Tom'}, {'age': 19, 'name': 'Lily'}]}]
<class 'dict'>
{'network': {'admin_state_up': True,
'name': 'net101',
'segments': [{'provider:network_type': 'vlan',
'provider:physical_network': 'public',
'provider:segmentation_id': 5},
{'provider:network_type': 'flat',
'provider:physical_network': 'default'}]}}
[{'provider:network_type': 'vlan',
'provider:physical_network': 'public',
'provider:segmentation_id': 5},
{'provider:network_type': 'flat', 'provider:physical_network': 'default'}]
{'students': [{'age': 18, 'name': 'Tom'}, {'age': 19, 'name': 'Lily'}]}