PyParsing 和嵌套括号:意外的 EOF 错误

PyParsing and nested parens: unexpected EOF error

我有参与者调查数据,其中包含每个变量的变量名称、它在该观察中的值,以及提出该问题所需的条件(如果较早的答案确定问题不适用,不会提示参与者)。我的任务之一是将表示 N/A 的空格与表示已询问但未回答提示的空格区分开来。不幸的是,我们的数据捕获工具中的导出功能不提供此功能。

为了解决这个问题,我将每个变量的分支条件与记录的观察结果进行比较,看看是否应该显示提示。这可能令人困惑,所以作为一个例子,想象一下主题 A 的记录:

Variable Name | Observation Value | Branching Logic
foo           |         5         | 
bar           |         2         | foo != 2
baz           |         7         | foo < 10 or bar == 5

foo 的提示无论如何都会出现; bar 的提示将显示,因为 foo = 5 满足其条件 foo != 2,并且类似地 baz 将被观察到。我将其视为 pandas 数据框,因此我在构建模块的玩具版本时使用字典来表示测试数据。我几乎可以正常工作,但缺少一件:嵌套括号。

有很多类似的问题(例如 pyparsing and line breaks),我在处理逻辑符号的 PyParsing 文档中找到了一个非常相似的示例,但我不擅长 python 并且有使用多个 类、子 类 等后出现问题。我能够将其用作以下内容的起点:

import pyparsing as pp
test_data = {
    'a' : 3,
    'b' : 6,
    'c' : 2,
    'd' : 4 
    }

# Functions applied by parser
def toInt(x):
    return [int(k) for k in x]
def useKey(x):
    try: return [test_data[k] for k in x]
    except KeyError: print("Value not a key:", x)
def checkCond(parsed):
    allinone = parsed[0]
    print("Condition:", allinone)
    humpty = " ".join([str(x) for x in allinone])
    return eval(humpty)

# Building the parser
key = pp.Word(pp.alphanums + '_')('key')
op = pp.oneOf('> >= == != <= <')('op')
val = pp.Word(pp.nums + '-')('value')
joint = pp.oneOf("and or")
key.setParseAction(useKey)
val.setParseAction(toInt)
cond = pp.Group(key + op + val)('condition')
cond.addParseAction(checkCond)
logic = cond + pp.Optional(joint) + pp.Optional(cond)

# Tests
if __name__ == "__main__":
    tests = [
        ("a == 5", False),
        ("b < 3", False),
        ("c > 1", True),
        ("d != 2", True),
        ("a >= 1", True),
        ("b <= 5", False),
        ("a <= 6 and b == 2", False),
        ("a <= 6 or b == 2", True)]
        #("b > 2 and (a == 3 or d > 2 or c < 1)", True)]
    for expr, res in tests:
        print(expr)
        out = logic.parseString(expr)
        out = " ".join([str(x) for x in out])
        out = bool(eval(out))
        if bool(out) == bool(res):
            print("PASS\n")
        else: print("FAIL\n", 
            "Got:", bool(out), 
            "\nExpected:",bool(res), "\n")

经过大量试验和错误后,我得到了我期望的结果。不过请注意,最后一个测试已被注释掉;如果你取消注释并 运行 它,你会得到:

b > 2 and (a == 3 or d > 2 or c < 1)
Condition: [6, '>', 2]
Traceback (most recent call last):
  File "testdat/pptutorial.py", line 191, in <module>
    out = bool(eval(out))
  File "<string>", line 1
    True and
           ^
SyntaxError: unexpected EOF while parsing

我确定我错过了一些非常愚蠢的东西,但对于我来说,我无法弄清楚这件作品。括号似乎让解析器认为这是新语句的开始。还有其他答案建议寻找空值、打印出单个标记等,但我没有那样走运。我猜这与我在解析器中设置组的方式有关。我以前从未建造过,所以这对我来说绝对是未知领域!非常感谢您的帮助,如果我可以提供更多信息,请告诉我。

你的语法的任何部分都不允许在输入中使用括号,这就是为什么 pyparsing 在遇到括号时停止解析的原因。

您可以通过对 logic:

的定义稍作调整,在条件周围使用括号
cond_chain_with_parentheses = pp.Forward()
cond_chain = cond + pp.Optional(joint + cond_chain_with_parentheses)
cond_chain_with_parentheses <<= cond_chain | '(' + cond_chain + ')'

logic = cond_chain_with_parentheses + pp.StringEnd()

在这里,我使用了 forward declaration of cond_chain_with_parentheses, which allows me to use it in the grammar definition even though it's not defined yet. I've also added StringEnd 以便在无法解析整个输入时抛出异常。


此语法可以正确解析您的所有输入:

>>> logic.parseString("b > 2 and (a == 3 or d > 2 or c < 1)")
Condition: [6, '>', 2]
Condition: [3, '==', 3]
Condition: [4, '>', 2]
Condition: [2, '<', 1]
([True, 'and', '(', True, 'or', True, 'or', False, ')'], {'condition': [True, True, True, False]})