Python递归函数被调用太多次

时间:2017-10-28 20:49:50

标签: python parsing dictionary nested

这是对此问题的跟进:Python parse text file into nested dictionaries

我最初接受了建议使用正则表达式格式化输入的答案,但在仔细观察输入之后,仍然存在一些我无法使用提议的正则表达式处理的问题。

所以我回来以递归方式将行解析为字典。

到目前为止我所拥有的是:

def parseToDictionary(input):
    key = ''
    value = ''
    result = {}

    if input[0].startswith('{'): # remove {
        del input[0]

    result.clear() # clear the dict for each recursion

    for idx, line in enumerate(input):
        line = line.rstrip() # remove trailing returns

        if line.startswith('['):
            key = line
            value = parseToDictionary(input[idx+1:]) # parse the next level
        elif line.startswith('}'): # reached the end of a block
            return result
        else:
            elements = line.split('\t')
            key = elements[0]
            if len(elements) > 1:
                value = elements[1]
            else:
                value = 'Not defined' # some keys may not have a value, so set a generic value here
        if key:
            result[key] = value

    return result

这是一个例子(非常简化!)输入:

[HEADER1]
{
key1    value
key2    long value, with a comma
[HEADER2]
{
key 1234
emptykey
}
}

输出结果为:

'[HEADER2]': 
{
    'emptykey': 'Not defined', 
    'key': '1234'
}, 
'key2': 'long value, with a comma', 
'key1': 'value', 
'[HEADER1]': 
{
    'emptykey': 'Not defined', 
    'key2': 'long value, with a comma', 
    'key1': 'value', 
    'key': '1234', 
    '[HEADER2]': 
    {
        'emptykey': 'Not defined', 
        'key': '1234'
    }
 }, 
 'emptykey': 'Not defined', 
 'key': '1234'
 }

但它应该是:

'[HEADER1]': 
{
    'key1': 'value', 
    'key2': 'long value, with a comma', 
    '[HEADER2]': 
    {
        'emptykey': 'Not defined', 
        'key': '1234'
    }
 }

因此,以[开头的每一行都是下一个块的关键。每个块内部都有多个键值对,还可能有另一个嵌套级别。出了什么问题是一些块被多次解析,我无法弄清楚它出错的地方。

输入参数为mydatafile.split('\n')

谁能帮助我?

1 个答案:

答案 0 :(得分:2)

您必须跳过在小节中处理的行:

def parse_to_dictionary(lines):
    def parse_block(lines):
        contents = {}
        if next(lines).strip() != '{':
            raise AssertionError("'{' expected")
        for line in lines:
            line = line.strip()
            if line == '}':
                return contents
            elif line[0] == '[':
                contents[line] = parse_block(lines)
            else:
                parts = line.split('\t', 1)
                contents[parts[0]] = None if len(parts) == 1 else parts[1]

    lines = iter(lines)
    key = next(lines)                
    if key[0] != '[':
        raise AssertionError("format error")
    return {key: parse_block(lines)}