在python中解析未知的数据结构

时间:2009-06-26 19:19:49

标签: python parsing data-structures

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

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

事实是,我不知道有多少层括号,以及数据的结构。我需要修改数据,并在将所有内容写入新文件之前,根据涉及数据成员的条件删除整个“条目”。在这样的文件中阅读的最佳方式是什么?谢谢!

6 个答案:

答案 0 :(得分:3)

数据结构基本上似乎是一个字典,它们的键是字符串,值是一个字符串或同一类型的另一个字典,所以我建议把它拉成那种python结构,

例如:

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

在文件的顶层,您将创建一个空白字典,然后对于您阅读的每一行,您使用标识符作为键,然后当您看到{您创建该键的值作为字典时。当您看到Key:Value时,您只需正常插入值,而不是将该键创建为dict。当你看到一个}你必须'回到'上一个词典时,你正在努力并回去填补它。

我认为整个解析器将文件放入这样的python结构中可以在一个相当短的递归函数中完成,当它看到{然后返回到它时,它只是调用自己来填充每个子字典看见时打电话

答案 1 :(得分:3)

这是一个语法。

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

我对列表中嵌入的词组和列表之后的逗号有点不确定,因为您没有提供任何示例。

答案 2 :(得分:2)

如果你有数据文件结构的语法,或者你可以自己创建它,你可以使用Python的解析器生成器,比如YAPPS:link text

答案 3 :(得分:1)

这取决于数据的结构,以及您需要做哪些更改。

一个选项可能是将其解析为Python数据结构,它看起来很相似,除了你没有字符串的引号。这使得复杂的操作变得容易。

另一方面,如果您只需进行更改以将某些条目修改为其他条目,则可以通过搜索和替换来执行此操作。

因此,在了解最佳方法之前,您需要更好地了解问题。

答案 4 :(得分:1)

这是一个与XML处理非常相似的问题,并且有很多Python代码可以做到这一点。因此,如果您能以某种方式将文件转换为XML,则可以通过标准库中的解析器运行它。您的示例的XML版本将是这样的:

<group id="Group1">  
    <entry id="Entry1">
        <title id="Title1"><data id="Data1">Member1</data> <data id="Data2">Member2</data></title>
        <title id="Title2"><data id="Data3">Member3</data> <data id="Data4">Member4</data></title>
    </entry>  
    <entry id="Entry2">  
        ...
    </entry>
</group>

当然,转换为XML可能不是最简单的事情。但是你的工作与XML解析器已经完成的工作非常类似,你只需要处理不同的语法。因此,您可以查看一些XML解析代码,并基于此为您的数据文件编写一些Python解析器。 (根据XML解析器的实现方式,您甚至可以复制代码,只需更改一些正则表达式,然后为您的文件运行它)

答案 5 :(得分:1)

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

基本上它的工作原理如下:它使用堆栈来跟踪最内部的指令块(或者在你的情况下是数据),并将每个新指令附加到顶部的块上。如果它解析一个需要新块的指令,则将其推送到堆栈。如果一个块结束,它会从堆栈中弹出一个元素。

我不想发布整个来源,因为它很大并且可以在谷歌代码上使用(lizzard-entertainment,修订版405)。您需要了解一些事项。

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

占位符

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();
}