web-dev-qa-db-ger.com

Erstellen Sie ein Diktat aus der Liste der Liste

Ich habe eine Textdatei, die ich eingelesen habe. Dies ist eine Protokolldatei, die einem bestimmten Muster folgt. Ich muss letztendlich ein JSON erstellen, aber bei der Erforschung dieses Problems wird es, sobald es sich in einem Diktat befindet, erforderlich, json.loads() oder json.dumps() zu verwenden. 

Ein Beispiel für die Textdatei finden Sie unten. 

INFO:20180606_141527:submit:is_test=False
INFO:20180606_141527:submit:username=Mary
INFO:20180606_141527:env:sys.platform=linux2
INFO:20180606_141527:env:os.name=ubuntu

Die Diktatur, nach der ich letztendlich suche, ist 

{
  "INFO": {
    "submit": {
      "is_test": false,
      "username": "Mary"
    },
    "env": {
      "sys.platform": "linux2",
      "os.name": "ubuntu"
    }
  }
}

Ich ignoriere die Zeitstempelinformationen in jeder Liste vorerst. 

Dies ist ein Ausschnitt des Codes, den ich verwende. 

import csv
tree_dict = {}
with open('file.log') as file:
    for row in file:
        for key in reversed(row.split(":")):
            tree_dict = {key: tree_dict}

Was zu einer unerwünschten Ausgabe führt, 

{'INFO': {'20180606_141527': {'submit': {'os.name=posix\n': {'INFO': {'20180606_141527': {'submit': {'sys.platform=linux2\n': {'INFO': {'20180606_141527': {'submit': {'username=a227874\n': {'INFO': {'20180606_141527': {'submit': {'is_test=False\n': {}}}}}}}}}}}}}}}}}

Ich muss das Diktat dynamisch auffüllen, da ich die tatsächlichen Feld-/Schlüsselnamen nicht kenne. 

16
Bryce Ramgovind
with open('demo.txt') as f:
    lines = f.readlines()

dct = {}

for line in lines:
    # param1 == INFO
    # param2 == submit or env
    # params3 == is_test=False etc.
    param1, _, param2, params3 = line.strip().split(':')

    # create dct[param1] = {} if it is not created
    dct.setdefault(param1, {})

    # create dct[param1][param2] = {} if it is no created
    dct[param1].setdefault(param2, {})

    # for example params3 == is_test=False
    # split it by '=' and now we unpack it
    # k == is_test
    # v == False
    k, v = params3.split('=')

    # and update our `dict` with the new values
    dct[param1][param2].update({k: v})

print(dct)

Ausgabe

{
'INFO': {
    'submit': {
        'is_test': 'False', 'username': 'Mary'
        }, 
    'env': {
        'sys.platform': 'linux2', 'os.name': 'ubuntu'
        }
    }
}  
12
Druta Ruslan

Dies ist einer der seltenen Fälle, in denen eine Rekursion in Python angemessen und hilfreich erscheint. Die folgende Funktion fügt dem hierarchischen Wörterbuch value eine d hinzu, die in der Liste der keys angegeben ist:

def add_to_dict(d, keys, value): 
    if len(keys) == 1: # The last key
        d[keys[0]] = value
        return
    if keys[0] not in d:
        d[keys[0]] = {} # Create a new subdict
    add_to_dict(d[keys[0]], keys[1:], value)

Die Funktion arbeitet mit Wörterbüchern beliebiger Tiefe. Der Rest ist nur das Aufrufen der Funktion:

d = {}
for line in file:
    keys, value = line.split("=")
    keys = keys.split(":")
    add_to_dict(d, keys, value.strip())

Ergebnis:

{'INFO': {'20180606_141527': {
                       'submit': {'is_test': 'False', 
                                  'username': 'Mary'}, 
                       'env': {'sys.platform': 'linux2', 
                               'os.name': 'ubuntu'}}}}

Sie können den Code ändern, um bestimmte Ebenen (z. B. den Zeitstempel) auszuschließen.

6
DYZ

Sie könnten ein verschachteltes collections.defaultdict() hier verwenden:

from collections import defaultdict
from pprint import pprint

d = defaultdict(lambda: defaultdict(dict))
with open('sample.txt') as in_file:
    for line in in_file:
        info, _, category, pair = line.strip().split(':')
        props, value = pair.split('=')
        d[info][category][props] = value

pprint(d)

Was gibt folgendes:

defaultdict(<function <lambda> at 0x7ff8a341aea0>,
            {'INFO': defaultdict(<class 'dict'>,
                                 {'env': {'os.name': 'ubuntu',
                                          'sys.platform': 'linux2'},
                                  'submit': {'is_test': 'False',
                                             'username': 'Mary'}})})

Hinweis:defaultdict() ist eine Unterklasse der eingebauten dict, daher ist dies kein Grund, sie im Endergebnis in dict zu konvertieren. Darüber hinaus kann defaultdict() auch mit json.dumps() in JSON serialisiert werden. 

4
RoadRunner

Sie können itertools.groupby verwenden:

import itertools, re
content = [re.split('\=|:', i.strip('\n')) for i in open('filename.txt')]
new_content = [[a, *c] for a, _, *c in content]
def group_vals(d):
  new_d = [[a, [c for _, *c in b]] for a, b in itertools.groupby(sorted(d, key=lambda x:x[0]), key=lambda x:x[0])]
  return {a:b[0][0] if len(b) ==1 else group_vals(b) for a, b in new_d}

import json
print(json.dumps(group_vals(new_content), indent=4))

Ausgabe:

{
 "INFO": {
     "env": {
        "os.name": "ubuntu",
        "sys.platform": "linux2"
     },
     "submit": {
         "is_test": "False",
         "username": "Mary"
     }
  }
}
3
Ajax1234

Quelle : 

import os

with open('file.log') as file:
    tree_dict = {}
    is_test = False
    username = ""              
    sysplatform = ""
    osname = ""
    for row in file: 
        row = row.rstrip('\n')
        for key in reversed(row.split(":")):            
            if not key.find('is_test'):
                is_test = key.split('=')[1]
            Elif not key.find('username'):
                username =key.split('=')[1]
            Elif not key.find('sys.platform'):
                sysplatform = key.split('=')[1]
            Elif not key.find('os.name'):
                osname = key.split('=')[1]    

     tree_dict = {
         "INFO": {
              "submit": {
                       "is_test": is_test,
                        "username": username
              },
              "env": {
                      "sys.platform":  sysplatform,
                      "os.name": osname
             }
        }
    }
    print(tree_dict)

Ergebnis: 

 {'INFO': {'submit': {'is_test': 'False', 'username': 'Mary'}, 'env': {'sys.platform': 'linux2', 'os.name': 'ubuntu'}}}
0
clem
import re
from functools import reduce

with open('file.txt') as f:
    lines = f.readlines()

def rec_merge(d1, d2):
    for k, v in d1.items():
        if k in d2:
            d2[k] = rec_merge(v, d2[k])
    d3 = d1.copy()
    d3.update(d2)
    return d3

lst_of_tup = re.findall(r'^([^:]*):[\d_]+:([^:]*):([^=]*)=(.*)$', lines, re.MULTILINE)
lst_of_dct = [reduce(lambda x,y: {y:x}, reversed(t)) for t in lst_of_tup]

dct = reduce(rec_merge, lst_of_dct)

pprint(dct)
# {'INFO': {'env': {'os.name': 'ubuntu', 'sys.platform': 'linux2'},
#           'submit': {'is_test': 'False', 'username': 'Mary'}}}
0
Sunitha

Überprüfen Sie das Vorhandensein von Schlüsseln:

import csv
import json

tree_dict = {}
with open('file.log') as file:
    tree_dict = {}
    for row in file:
        keys = row.split(":")

        if keys[0] not in tree_dict:
            tree_dict[keys[0]] = {}

        if keys[-2] not in tree_dict[keys[0]]:
            tree_dict[keys[0]][keys[-2]] = {}

        key, value = keys[-1].split("=")

        if value == "False":
            value = False
        if value == "True":
            value = True

        tree_dict[keys[0]][keys[-2]][key] = value

dumped = json.dumps(tree_dict)
0
ted