使用缩进文本文件

时间:2016-07-29 17:32:57

标签: python json parsing data-structures nested

我想迭代一个文件并将每行的内容放入一个深层嵌套的dict中,其结构由前导空格定义。这种愿望与记录here非常相似。我已经解决了这个问题,但现在遇到的问题是重写密钥被覆盖而不是被强制转换为列表。

本质:

a:
    b:      c
    d:      e
a:
    b:      c2
    d:      e2
    d:      wrench

被投射到

时,

会被投射到{"a":{"b":"c2","d":"wrench"}}

{"a":[{"b":"c","d":"e"},{"b":"c2","d":["e2","wrench"]}]}

一个独立的例子:

import json

def jsonify_indented_tree(tree):
    #convert indentet text into json
    parsedJson= {}
    parentStack = [parsedJson]
    for i, line in enumerate(tree):
        data = get_key_value(line)
        if data['key'] in parsedJson.keys(): #if parent key is repeated, then cast value as list entry
            # stuff that doesn't work
#            if isinstance(parsedJson[data['key']],list):
#                parsedJson[data['key']].append(parsedJson[data['key']])
#            else:
#                parsedJson[data['key']]=[parsedJson[data['key']]]
            print('Hey - Make a list now!')
        if data['value']: #process child by adding it to its current parent
            currentParent = parentStack[-1] #.getLastElement()
            currentParent[data['key']] = data['value']
            if i is not len(tree)-1:
                #determine when to switch to next branch
                level_dif = data['level']-get_key_value(tree[i+1])['level'] #peek next line level
                if (level_dif > 0):
                    del parentStack[-level_dif:] #reached leaf, process next branch
        else:
        #group node, push it as the new parent and keep on processing.
            currentParent = parentStack[-1] #.getLastElement()
            currentParent[data['key']] = {}
            newParent = currentParent[data['key']]
            parentStack.append(newParent)
    return parsedJson

def get_key_value(line):
    key = line.split(":")[0].strip()
    value = line.split(":")[1].strip()
    level = len(line) - len(line.lstrip())
    return {'key':key,'value':value,'level':level}

def pp_json(json_thing, sort=True, indents=4):
    if type(json_thing) is str:
        print(json.dumps(json.loads(json_thing), sort_keys=sort, indent=indents))
    else:
        print(json.dumps(json_thing, sort_keys=sort, indent=indents))
    return None

#nested_string=['a:', '\tb:\t\tc', '\td:\t\te', 'a:', '\tb:\t\tc2', '\td:\t\te2']
#nested_string=['w:','\tgeneral:\t\tcase','a:','\tb:\t\tc','\td:\t\te','a:','\tb:\t\tc2','\td:\t\te2']
nested_string=['a:',
 '\tb:\t\tc',
 '\td:\t\te',
 'a:',
 '\tb:\t\tc2',
 '\td:\t\te2',
  '\td:\t\twrench']

pp_json(jsonify_indented_tree(nested_string))

1 个答案:

答案 0 :(得分:1)

这种方法(逻辑上)更直接(虽然更长):

  1. 跟踪多行字符串中每行的levelkey - value
  2. 将此数据存储在level键控列表中: {level1:[dict1dict2]}
  3. 仅在仅限关键字行中附加代表该键的字符串:{level1:[dict1dict2"nestKeyA"] }
  4. 由于仅限密钥行意味着下一行更深一层,因此请在下一级处理:{level1:[dict1,{{1} },dict2],"nestKeyA":[......]}。某些更深层次level2的内容本身可能只是另一个仅限密钥行(并且下一个循环将添加新级别level2,使其成为{{{ 1}}:[level3level1dict1],dict2:["nestKeyA"],level2:[......]} )或新的字典"nestKeyB",{level3:[dict3level1dict1],dict2:[{{1} }]
  5. 步骤1-4继续,直到当前行缩进小于前一行(表示返回某个先前作用域)。这就是我的每行迭代示例中数据结构的样子。

    "nestKeyA"

    然后需要做两件事。 1 :需要检查dict列表是否包含重复键以及列表中组合的任何重复的dict值 - 这将在稍后进行演示。 2 :从迭代4和5之间可以看出,最深层次的词典列表(此处level2)被合并为一个词典...最后,为了演示重复处理观察:

    dict3

    其中0, {0: []} 1, {0: [{'k': 'sds'}]} 2, {0: [{'k': 'sds'}, 'a']} 3, {0: [{'k': 'sds'}, 'a'], 1: [{'b': 'c'}]} 4, {0: [{'k': 'sds'}, 'a'], 1: [{'b': 'c'}, {'d': 'e'}]} 5, {0: [{'k': 'sds'}, {'a': {'d': 'e', 'b': 'c'}}, 'a'], 1: []} 6, {0: [{'k': 'sds'}, {'a': {'d': 'e', 'b': 'c'}}, 'a'], 1: [{'b': 'c2'}]} 7, {0: [{'k': 'sds'}, {'a': {'d': 'e', 'b': 'c'}}, 'a'], 1: [{'b': 'c2'}, {'d': 'e2'}]} 1放置在一个列表中,该列表本身会进入由原始密钥键入的字典。

  6. 重复步骤1-5,将更深的范围内的字符串向上提升到其父键上,直到达到当前行的范围(级别)。

  7. 处理终止条件,将第0级dict列表合并为dict。
  8. 以下是代码:

    [7b, {0: [{'k': 'sds'}, {'a': {'d': 'e', 'b': 'c'}}, 'a'], 1: [{'b': 'c2'}, {'d': 'e2'}, {'d': 'wrench'}]}]
    [7c, {0: [{'k': 'sds'}, {'a': {'d': 'e', 'b': 'c'}}, {'a': {'d': ['wrench', 'e2'], 'b': 'c2'}}], 1: []}]