高效提取空格缩进结构文件中的文本块

0 投票
2 回答
735 浏览
提问于 2025-04-17 19:43

我有一个很大的源代码文件,这个文件是用空格来组织结构的。我只对文件中特定的一部分内容感兴趣,内容大概是这样的:

   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 个回答

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(fields)),这是出于安全考虑。同时,我用了 .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]])

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

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}}}

撰写回答