【问题标题】:Processing repeatedly structured text file with python用python处理重复结构化的文本文件
【发布时间】:2014-10-03 18:39:33
【问题描述】:

我有一个大文本文件,其结构如下:

Student = {
        PInfo = {
                ID   = 0001;
            Name.First = "Joe";
            Name.Last = "Burger";
            DOB  = "01/01/2000";
        };
        School = "West High";
        Address = {
            Str1 = "001 Main St.";
            Zip = 12345;
        };
    };
    Student = {
        PInfo = {
            ID   = 0002;
            Name.First = "John";
            Name.Last = "Smith";
            DOB  = "02/02/2002";
        };
        School = "East High";
        Address = {
            Str1 = "001 40nd St.";
            Zip = 12346;
        };
        Club = "Football";
    };
    ....

Student 块共享相同的条目,如“PInfo”、“School”和“Address”,但其中一些可能有其他条目,例如“John Smith”的“Club”信息,“乔汉堡”。 我想要做的是获取每个学生的姓名、学校名称和邮政编码并将它们存储在字典中,例如

    {'Joe Burger':{School:'West High', Zip:12345}, 'John Smith':{School:'East High', Zip:12346}, ...}

作为python编程的新手,我尝试打开文件并逐行分析,但是看起来很麻烦。并且实际文件比我上面发布的示例要大得多,而且要复杂得多。我想知道是否有更简单的方法来做到这一点。先谢谢了。

【问题讨论】:

  • 如果是jsonyaml,有模块可以很容易地读取这些数据。
  • 我昨天问了一个类似的问题,但还没有收到任何答案 - stackoverflow.com/questions/26173372/parsing-an-ad-hoc-tree 。支持您的问题
  • @spade:你得到了完全不同的东西。并且没有神奇的算法可以自动理解无中生有的结构或模式。必须自己做;对不起。
  • @DonQuestion,我清楚地看到这两个问题之间有很多相似之处,因为它们都可以表示为 n 叉树。这些图案对人眼来说非常明显——应该可以训练机器学习阅读它。我希望来自编译器甚至 NLP 领域的人就从嵌套结构构建通用树提出建议。无论如何,我并不是要劫持这个线程,所以会在这里打住。
  • 您可以尝试PyParsing 或其他Python parsers 为您的输入格式创建解析器。

标签: python parsing text parser-generator


【解决方案1】:

要解析文件,您可以定义描述输入格式的语法并使用它来生成解析器。

many language parsers in Python。例如,您可以使用Grako,它将EBNF 的变体中的语法作为输入,并在Python 中输出记忆PEG 解析器。

要安装 Grako,请运行 pip install grako

这是使用 Grako 的 EBNF 语法风格的格式语法:

(* a file is zero or more records *)
file = { record }* $;
record = name '=' value ';' ;
name = /[A-Z][a-zA-Z0-9.]*/ ;
value = object | integer | string ;
(* an object contains one or more records *)
object = '{' { record }+ '}' ;
integer = /[0-9]+/ ;
string = '"' /[^"]*/ '"';

要生成解析器,请将语法保存到文件中,例如 Structured.ebnf 并运行:

$ grako -o structured_parser.py Structured.ebnf

它创建structured_parser 模块,可用于从输入中提取学生信息:

#!/usr/bin/env python
from structured_parser import StructuredParser

class Semantics(object):
    def record(self, ast):
        # record = name '=' value ';' ;
        # value = object | integer | string ;
        return ast[0], ast[2] # name, value
    def object(self, ast):
        # object = '{' { record }+ '}' ;
        return dict(ast[1])
    def integer(self, ast):
        # integer = /[0-9]+/ ;
        return int(ast)
    def string(self, ast):
        # string = '"' /[^"]*/ '"';
        return ast[1]

with open('input.txt') as file:
    text = file.read()
parser = StructuredParser()
ast = parser.parse(text, rule_name='file', semantics=Semantics())
students = [value for name, value in ast if name == 'Student']
d = {'{0[Name.First]} {0[Name.Last]}'.format(s['PInfo']):
     dict(School=s['School'], Zip=s['Address']['Zip'])
     for s in students}
from pprint import pprint
pprint(d)

输出

{'Joe Burger': {'School': u'West High', 'Zip': 12345},
 'John Smith': {'School': u'East High', 'Zip': 12346}}

【讨论】:

    【解决方案2】:

    它不是 json,而是类似的结构。您应该能够将其重新格式化为 json。

    1. "=" -> ":"
    2. 用 '"' 引用所有键
    3. ";" -> ","
    4. 删除所有后跟“}”的“,”
    5. 把它放在花括号里
    6. 用 json.loads 解析它

    【讨论】:

      【解决方案3】:

      对于这样的事情,我使用Marpa::R2PerlMarpa, a general BNF parser 的接口。它允许将文本描述为语法规则并将它们解析为数组树(解析树)。然后,您可以遍历树以将结果保存为哈希哈希(哈希是 python 字典的 perl)或按原样使用它。

      我使用您的输入制作了一个工作示例:parserresult tree.

      希望这会有所帮助。

      附: ast_traverse() 示例:Parse values from a block of text based on specific keys

      【讨论】:

        猜你喜欢
        • 2021-02-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-17
        • 2015-08-26
        • 2014-09-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多