本文转载自 jxzdsw - 从本文中提取所有json字符串,返回字典组成的列表

有些命令行可以返回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'}]}

·End·