2013-03-20 2 views
0

У меня есть большой файл исходного кода, который структурирован с использованием пробелов. Я заинтересован только в одной конкретной части структурированного текстового файла, который выглядит следующим образом:Эффективно извлекать блоки текста из структурированного файла с пространственным углублением

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

Как вы можете видеть, есть «СП» структура, определенная (они будут разбросаны по всему исходному коду, но имеют одно и то же имя), который содержит одну или несколько других структур того же типа. В этом примере есть только один, называемый «Spare». Каждая структура всегда будет содержать те же 5 элементов. Если значение не определено, оно равно нулю.

Каков наиболее элегантный способ извлечения имени структуры и ее значений элементов? После их извлечения они будут храниться в словаре для быстрого и легкого доступа.

Я пробовал использовать регулярное выражение, но я не уверен, что это очень эффективное решение этой конкретной проблемы. Какие подходы обычно принимаются для решения чего-то подобного?

ответ

3

Этот код, как представляется, использует скобки в виде альголов (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

Если вы хотите извлечь только 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]]) 

предложение: старайтесь избегать регулярных выражений при разборе.

Смежные вопросы