2016-02-29 4 views
0

Я пытаюсь создать скрипт python, который может анализировать следующий тип записи журнала, который содержит ключи и значения. Для каждого ключа может быть или не быть другой вложенной пары ключей и значений. Пример приведен ниже. Глубина вложенности может варьироваться в зависимости от журнала, который я получаю, поэтому он должен быть динамическим. Однако глубина заключена в фигурные скобки.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, которые уже могут выполнять такой синтаксический анализ?

ответ

1

Я создал питона пример сценария, который будет делать работу, просто настроить его как ваше подобие. Он преобразует ваш формат в вложенный 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}} 

И вы можете получить значение как нормальный Словаре будет :) надеюсь, что это помогает ...

+0

Вам действительно нужно включить код в свой ответ. Просто ссылка на него не достаточно хороша. – Blckknght

+0

@richmondwang, именно то, что я искал.Тем не менее, моя динамическая строка на этот раз ниже, и это дало мне синтаксическую ошибку: – user2605278

+0

Какие данные вы прошли? @ user2605278 – rrw

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 
+0

Спасибо Himanshu. Как я могу получить только ценность чешской республики (должен вернуть мне всего 0) – user2605278

+0

также для этого нужна предварительная обработка? Поскольку не все ключи заключены в двойные кавычки, например, - Соединения – user2605278

+0

Если вы знаете, что ключ Чешской Республики присутствует на первом уровне, тогда просто сделайте 'data.get ('Czech Republic')' – Himanshu

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])) 
Смежные вопросы