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 或其他带有一个很好的解析器的东西编写的,这可能很容易,但这是我必须使用的,所以我想知道是否有任何相对简单的方法来解析这个文件. 它类似于括号匹配,所以我想会有一些模块,但我没有找到任何东西。

我正在使用 python,但如果用另一种语言更容易解决这个问题,我可以切换到这个功能。

4

2 回答 2

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的众多解析工具之一。

于 2012-08-22T20:47:09.887 回答
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

...

这就是我需要的。感谢大家的回复,非常感谢您的帮助!

于 2012-08-23T22:58:49.637 回答