我有参与者调查数据,其中包含每个变量:变量名称,该观察值以及提出该问题所需的条件(如果先前的答案确定问题不适用,则不会提示参与者)。我的任务之一是区分表示 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
。我将其视为熊猫数据帧,因此在构建模块的玩具版本时,我使用字典来表示测试数据。我几乎让它工作,但缺少一块:嵌套括号。
有很多类似的问题(例如pyparseing和换行符),我在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("PASSn")
else: print("FAILn",
"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()
在这里,我使用了cond_chain_with_parentheses
的前向声明,它允许我在语法定义中使用它,即使它还没有定义。我还添加了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]})