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]})
我有参与者调查数据,其中包含每个变量的变量名称、它在该观察中的值,以及提出该问题所需的条件(如果较早的答案确定问题不适用,不会提示参与者)。我的任务之一是将表示 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]})