Python:嵌套键值数据解析

时间:2016-02-29 09:13:13

标签: python parsing nested

我正在尝试创建一个python脚本,它可以解析包含键和值的以下类型的日志条目。对于每个键,可能有也可能没有另一对嵌套的键和值。一个例子如下。嵌套的深度可以根据我得到的日志而变化,因此它必须是动态的。然而,深度用括号封装。

我将使用键和值的字符串是这样的:

   Countries =     {
    "USA" = 0;
    "Spain" = 0;
    Connections = 1;
    Flights =         {
        "KLM" = 11;
        "Air America" = 15;
        "Emirates" = 2;
        "Delta" = 3;
    };
    "Belgium" = 1;
    "Czech Republic" = 0;
    "Netherlands" = 1;
    "Hungary" = 0;
    "Luxembourg" = 0;
    "Italy" = 0;

};

以上数据也可以有多个巢穴。我想写一个函数来解析这个并将它放在一个数组(或类似的数组)中,这样我就可以得到一个特定键的值,如:

    print countries.belgium
          value should be printed as 1

同样地,

    print countries.flights.delta
          value should be printed as 3.

请注意,输入不需要在所有键(如连接或航班)中都有引号。

指向我可以开始的任何指示。任何已经可以像这样解析的python库了吗?

3 个答案:

答案 0 :(得分:1)

迭代数据并检查元素是否是另一个键值对,如果是,则递归调用该函数。像这样:

def parseNestedData(data):
    if isinstance(data, dict):
        for k in data.keys():
            parseNestedData(data.get(k))
    else:
        print data

输出:

>>> Countries =     {
"USA" : 0,
"Spain" : 0,
"Connections" : 1,
"Flights" :         {
    "KLM" : 11,
    "Air America" : 15,
    "Emirates" : 2,
    "Delta" : 3,
},
"Belgium" : 1,
"Czech Republic" : 0,
"Netherlands" : 1,
"Hungary" : 0,
"Luxembourg" : 0,
"Italy" :0
};

>>> Countries
{'Connections': 1,
'Flights': {'KLM': 11, 'Air America': 15, 'Emirates': 2, 'Delta': 3},
 'Netherlands': 1,
'Italy': 0,
'Czech Republic': 0,
'USA': 0,
'Belgium': 1,
'Hungary': 0,
'Luxembourg': 0, 'Spain': 0}
>>> parseNestedData(Countries)
1
11
15
2
3
1
0
0
0
1
0
0
0

答案 1 :(得分:1)

我已经创建了一个示例python脚本来完成这项工作,只需按照您的喜好进行调整即可。它将您的格式转换为嵌套的dict。它和你一样充满活力。

请看这里:Paste bin 代码:

import re
import ast

data = """ { Countries = { USA = 1; "Connections" = { "1 Flights" = 0; "10 Flights" = 0; "11 Flights" = 0; "12 Flights" = 0; "13 Flights" = 0; "14 Flights" = 0; "15 Flights" = 0; "16 Flights" = 0; "17 Flights" = 0; "18 Flights" = 0; "More than 25 Flights" = 0; }; "Single Connections" = 0; "No Connections" = 0; "Delayed" = 0; "Technical Fault" = 0; "Others" = 0; }; }"""


def arrify(string):
    string = string.replace("=", " : ")
    string = string.replace(";", " , ")
    string = string.replace("\"", "")
    stringDict = string.split()
    # print stringDict
    newArr = []
    quoteCosed = True
    for i, splitStr in enumerate(stringDict):
        if i > 0:
            # print newArr
            if not isDelim(splitStr):
                if isDelim(newArr[i-1]) and quoteCosed:
                    splitStr = "\"" + splitStr
                    quoteCosed = False

                if isDelim(stringDict[i+1]) and not quoteCosed:
                    splitStr += "\""
                    quoteCosed = True

        newArr.append(splitStr)   

    newString = " ".join(newArr)
    newDict = ast.literal_eval(newString)
    return normalizeDict(newDict)

def isDelim(string):
    return str(string) in "{:,}"


def normalizeDict(dic):
    for key, value in dic.items():
        if type(value) is dict:
            dic[key] = normalizeDict(value)
            continue
        dic[key] = normalize(value)
    return dic

def normalize(string):
    try:
        return int(string)
    except:
        return string

print arrify(data)

示例数据的结果:

{'Countries': {'USA': 1, 'Technical Fault': 0, 'No Connections': 0, 'Delayed': 0, 'Connections': {'17 Flights': 0, '10 Flights': 0, '11 Flights': 0, 'More than 25 Flights': 0, '14 Flights': 0, '15 Flights': 0, '12 Flights': 0, '18 Flights': 0, '16 Flights': 0, '1 Flights': 0, '13 Flights': 0}, 'Single Connections': 0, 'Others': 0}}

你可以获得像普通字典那样的价值:)希望它有帮助...

答案 2 :(得分:1)

定义一个处理和存储信息的类结构,可以给你这样的东西:

import re

class datastruct():
    def __init__(self,data_in):
        flights = re.findall('(?:Flights\s=\s*\{)([\s"A-Z=0-9;a-z]*)};',data_in)
        flight_dict = {}
        for flight in flights[0].split(';')[0:-1]:
            key,val = self.split_data(flight)
            flight_dict[key] = val

        countries = re.findall('("[A-Za-z]+\s?[A-Za-z]*"\s=\s[0-9]{1,2})',data_in)
        countries_dict = {}
        for country in countries:
            key,val = self.split_data(country)
            if key not in flight_dict:
                countries_dict[key]=val

        connections = re.findall('(?:Connections\s=\s)([0-9]*);',data_in)
        self.country= countries_dict
        self.flight = flight_dict
        self.connections = int(connections[0])

    def split_data(self,data2):
        item = data2.split('=')
        key = item[0].strip().strip('"')
        val = int(item[1].strip())
        return key,val

请注意,如果数据不完全如我在下面假设的那样,可能需要调整正则表达式。可以如下设置和引用数据:

raw_data = 'Countries =     {    "USA" = 0;    "Spain" = 0;    Connections = 1;    Flights =         {        "KLM" = 11;        "Air America" = 15;        "Emirates" = 2;        "Delta" = 3;    };    "Belgium" = 1;    "Czech Republic" = 0;    "Netherlands" = 1;    "Hungary" = 0;    "Luxembourg" = 0;    "Italy" = 0;};'

flight_data = datastruct(raw_data)
print("No. Connections:",flight_data.connections)
print("Country 'USA':",flight_data.country['USA'],'\n'
print("Flight 'KLM':",flight_data.flight['KLM'],'\n')

for country in flight_data.country.keys():
    print("Country: {0} -> {1}".format(country,flight_data.country[country]))