2012-08-22 68 views
2

請原諒我,如果這已被問到,我看,我無法在任何地方找到類似的問題。我需要解析一個包含條件語句的文件,有時嵌套在另一個文件中。解析嵌套的條件語句

我有一個存儲配置數據的文件,但配置數據稍有不同,具體取決於用戶定義的選項。我可以處理條件語句,它們都是沒有操作的布爾值,但我不知道如何遞歸地評估嵌套條件。例如,一塊的文件可能看起來像:

... 
#if CELSIUS 
    #if FROM_KELVIN ; this is a comment about converting kelvin to celsius. 
     temp_conversion = 1, 273 
    #else 
     temp_conversion = 0.556, -32 
    #endif 
#else 
    #if FROM_KELVIN 
     temp_conversion = 1.8, -255.3 
    #else 
     temp_conversion = 1.8, 17.778 
    #endif 
#endif 
... 

...此外,一些條件語句不具有#else聲明,只是#if CONDITION statement(s) #endif

我意識到,如果文件只是用XML或其他具有良好解析器的文件寫入,這可能很容易,但這是我必須使用的,所以我想知道是否有任何相對簡單的方法解析這個文件。它與括號匹配類似,所以我想有一些模塊可以使用,但是我沒有找到任何東西。

任何幫助,將不勝感激。提前致謝!

PS。我在Python中工作,但如果在另一種語言中更容易解決此問題,我可以切換此功能。

+1

這種格式是否有名稱或標準?以及像FROM_KELVIN定義的常量在哪裏/哪裏?最後,爲什麼每個賦值都有兩個值 - 它是否應該將一個元組賦值給'temp_conversion'? –

+0

不知道這是否是一個好主意,但是您可以使用一些正則表達式替換(這需要四次替換)將此代碼轉換爲Python代碼,然後在沙盒環境中對其進行評估。 – Blender

+0

@DavidRobinson該格式沒有我知道的標準,我正在嘗試製作一個小的開源程序,該程序將與現有專有應用程序使用的傳統格式兼容,並且這是他們使用的格式。處理條件和語句不是問題,我只是保留條件的布爾字典,並且我已經有了一個用於temp_conversion的正則表達式解析器。 – jmp

回答

1

由於所有的條件都是二進制的,並且我事先知道所有這些條件的值(無需像編程語言那樣按順序對它們進行評估),所以我可以用正則表達式來完成它。這對我更好。它找到最低級別條件(沒有嵌套條件的條件),評估它們並用正確的內容替換它們。然後重複更高級的條件等等。

import re 

conditions = ['CELSIUS', 'FROM_KELVIN'] 

def eval_conditional(matchobj): 
    statement = matchobj.groups()[1].split('#else') 
    statement.append('') # in case there was no else statement 
    if matchobj.groups()[0] in conditions: return statement[0] 
    else: return statement[1] 

def parse(text): 
    pattern = r'#if\s*(\S*)\s*((?:.(?!#if|#endif))*.)#endif' 
    regex = re.compile(pattern, re.DOTALL) 
    while True: 
     if not regex.search(text): break 
     text = regex.sub(eval_conditional, text) 
    return text 

if __name__ == '__main__': 
    i = open('input.txt', 'r').readlines() 
    g = ''.join([x.split(';')[0] for x in i if x.strip()]) 
    o = parse(g) 
    open('output.txt', 'w').write(o) 

鑑於在原崗位的輸入,輸出:

... 
     temp_conversion = 1, 273 

... 

這正是我需要的。感謝大家的迴應,我真的很感謝幫助!

6

下面是這個語法簡單的遞歸解析:

def parse(lines): 
    result = [] 
    while lines: 
     if lines[0].startswith('#if'): 
      block = [lines.pop(0).split()[1], parse(lines)] 
      if lines[0].startswith('#else'): 
       lines.pop(0) 
       block.append(parse(lines)) 
      lines.pop(0) #endif 
      result.append(block) 
     elif not lines[0].startswith(('#else', '#endif')): 
      result.append(lines.pop(0)) 
     else: 
      break 
    return result 

tree = parse([x.strip() for x in your_code.splitlines() if x.strip()]) 

從你的例子會創建以下樹結構:

[['CELSIUS', 
    [['FROM_KELVIN', 
    ['temp_conversion = 1, 273'], 
    ['temp_conversion = 0.556, -32']]], 
    [['FROM_KELVIN', 
    ['temp_conversion = 1.8, -255.3'], 
    ['temp_conversion = 1.8, 17.778']]]]] 

這應該是容易評估。

對於更高級的解析,請考慮可用於Python的parsing tools之一。

+0

謝謝!這有幫助,但該文件有多個條件,並且這個函數會將它們全部結合到相同的結構中。另外,如果代碼在不破壞解析器的情況下可能會很笨拙地形成,那麼這段代碼希望一切都很好地被換行符等分開。也許解析器是要走的路,它看起來像YAPPS(從你發佈的鏈接)可以很好地工作。 – jmp