从空间缩进的结构化文件中有效地提取文本块

时间:2013-03-20 09:11:05

标签: python parsing text

我有一个使用空格构建的大型源代码文件。我只对结构化文本文件的一个特定部分感兴趣,如下所示:

   SP : STRUCT  
    Spare : STRUCT  //Spare
     Val : INT  := 100; 
     UpLim : INT  := 100;   
     LoLim : INT ;  
     Def : INT  := 100; 
     Prot : INT  := 2;  
    END_STRUCT ;    
   END_STRUCT ; 

如您所见,定义了一个'SP'结构(这些结构将在整个源代码中点缀,但具有相同的名称),其中包含一个或多个相同类型的其他结构。在这个例子中只有一个叫做“Spare”。每个结构将始终包含相同的5个元素。如果没有定义值,则为零。

提取结构名称及其元素值的最优雅方法是什么?提取后,它们将存储在字典中,以便快速方便地访问。

我尝试过使用正则表达式,但我不确定这是解决这一特定问题的非常有效的方法。通常采取什么方法来解决这样的问题?

2 个答案:

答案 0 :(得分:3)

此代码似乎使用类似algol的大括号(struct/end_struct)。我不认为缩进在语法上很重要。因此,解析器应该基于关键字,例如:

import re

def parse(data):
    stack = [{}]

    for x in data.splitlines():
        x = re.sub(r'\s+', '', x)

        m = re.match(r'(\w+):STRUCT', x)
        if m:
            d = {}
            stack[-1][m.group(1)] = d
            stack.append(d)
            continue

        m = re.match(r'(\w+):INT(?::=(\w+))?', x)
        if m:
            stack[-1][m.group(1)] = int(m.group(2) or 0)
            continue

        m = re.match(r'END_STRUCT', x)
        if m:
            stack.pop()
            continue

    return stack[0]

结果:

data = """
   SP : STRUCT  
    Spare : STRUCT  //Spare
     Val : INT  := 100; 
     UpLim : INT  := 100;   
     LoLim : INT ;  
     Def : INT  := 100; 
     Prot : INT  := 2;  
    END_STRUCT ;    
   END_STRUCT ; 
"""

print parse(data)
# {'SP': {'Spare': {'LoLim': 0, 'Prot': 2, 'Def': 100, 'UpLim': 100, 'Val': 100}}}

答案 1 :(得分:1)

如果你只想提取SP:STRUCT而你想手动解析它(当你这样做时要小心),你可以使用这样的东西:

data = {}
found = False
with open("code.txt", "r") as code:
    for line in code.readline():
        clean = line.split("//")[0].strip().rstrip(";").split(":")
        fields = map(lambda f: f.strip(), clean)
        if found and fields[0].upper() == "END_STRUCT":
            break
        elif len(fields) == 2:
            if fields[0].upper() == "SP" and fields[1].upper() == "STRUCT":
                found = True
        elif len(fields) == 3 and found:
            if fields[1].upper() != "STRUCT":
                data[fields[0]] = fields[2].lstrip("=").strip()

我出于安全原因使用.upper()并检查len(字段),而我使用.strip()主要是为了忽略缩进(似乎不需要:代码在没有它的情况下可以有效)。

你也可以添加这段代码(在最后一行的同一缩进级别)以正确的格式存储信息:

if fields[1].upper() == "INT":
    data[fields[0]] = int(data[fields[2]])
#elif field[1].upper == "SOMETHING_ELSE":
#    data[fields[0]] = convert(data[fields[2]])

建议:在解析时尽量避免使用正则表达式。