在python中解析未知数据结构

2024-09-23 10:21:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个包含大量数据的文件,其格式类似于:

Group1 {  
    Entry1 {  
        Title1 [{Data1:Member1, Data2:Member2}]  
        Title2 [{Data3:Member3, Data4:Member4}]  
    }  
    Entry2 {  
        ...  
    }  
}
Group2 {
    DifferentEntry1 {
        DiffTitle1 {
            ...
        }
    }
}

问题是,我不知道括号有多少层,数据是如何组织的。在写入新数据之前,我需要修改所有涉及到新成员的数据和条件。在这样的文件中阅读的最佳方式是什么?谢谢!在


Tags: 文件数据格式group1data1data2entry1title2
3条回答

我有一些类似的东西,但是是用java写的。它解析具有相同基本结构的文件,但语法略有不同(没有'{'和'}',只是像python中那样的缩进)。它是一种非常简单的脚本语言。在

基本上它是这样工作的:它使用堆栈来跟踪最内部的指令块(或者在您的案例中是数据),并将每个新的指令追加到顶部的块中。如果它分析了一条需要新块的指令,它将被推送到堆栈中。如果一个块结束,它将从堆栈中弹出一个元素。在

我不想发布整个来源,因为它是大的,它可以在谷歌代码(利扎德娱乐,修订版405)。有几件事你需要知道。在

  • Instruction是一个抽象类,它有一个block-expected方法来指示具体指令是否需要块(如循环等),在您的情况下,这是不必要的,您只需要检查'{'。在
  • 块扩展指令。它包含一个指令列表,并有一个add方法来添加更多的指令。在
  • indent_level返回指令文本前面的空格数。这对于{}sings也是不必要的。在

占位符

BufferedReader input = null;
try {
    input = new BufferedReader(new FileReader(inputFileName));
    // Stack of instruction blocks
    Stack<Block> stack = new Stack<Block>();
    // Push the root block
    stack.push(this.topLevelBlock);
    String line = null;
    Instruction prev = new Noop();
    while ((line = input.readLine()) != null) {
        // Difference between the indentation of the previous and this line
        // You do not need this you will be using {} to specify block boundaries
        int level = indent_level(line) - stack.size();
        // Parse the line (returns an instruction object)
        Instruction inst = Instruction.parse(line.trim().split(" +"));
        // If the previous instruction expects a block (for example repeat)
        if (prev.block_expected()) {
            if (level != 1) {
                // TODO handle error
                continue;
            }
            // Push the previous instruction and add the current instruction
            stack.push((Block)(prev));
            stack.peek().add(inst);
        } else {
            if (level > 0) {
                // TODO handle error
                continue;
            } else if (level < 0) {
                // Pop the stack at the end of blocks
                for (int i = 0; i < -level; ++i)
                    stack.pop();
            }
            stack.peek().add(inst);
        }
        prev = inst;
    }
} finally {
    if (input != null)
        input.close();
}

数据结构基本上看起来像一个dict,其中键是字符串,值要么是字符串,要么是同一类型的另一个dict,所以我建议把它拉到那种python结构中

例如:

{'group1': {'Entry2': {}, 'Entry1': {'Title1':{'Data4': 'Member4',
'Data1': 'Member1','Data3': 'Member3', 'Data2': 'Member2'}, 
'Title2': {}}}

在文件的顶层,您将创建一个空白dict,然后对于您读取的每一行,您使用标识符作为键,然后当您看到{时,将该键的值创建为dict键:值,而不是将该键创建为dict,而是正常插入值。当你看到一个}时,你必须“回到”你正在做的上一个dict,然后再回去填写它。在

我认为将文件放入python结构中的整个解析器可以在一个相当短的递归函数中完成,该函数在看到{时调用自己来填充每个子dict,然后在看到}时返回给它的调用者

这是一个语法。在

dict_content : NAME ':' NAME [ ',' dict_content ]?
             | NAME '{' [ dict_content ]? '}' [ dict_content ]?
             | NAME '[' [ list_content ]? ']' [ dict_content ]?
             ;

list_content : NAME [ ',' list_content ]?
             | '{' [ dict_content ]? '}' [ ',' list_content ]?
             | '[' [ list_content ]? ']' [ ',' list_content ]?
             ;

顶层是dict_content。在

我对嵌入到列表中的dicts和list后面的逗号有点不确定,因为您没有提供任何示例。在

相关问题 更多 >