Python:尝试创建等价的和(或(值,值,值))

时间:2013-06-27 05:14:28

标签: python boolean-logic

好的,这就是我的困境:

我正在为一个subreddit开发FAQ bot。我遇到布尔逻辑问题,可以使用一对更有经验的眼睛(这是我在Python中的第一次冒险)。现在机器人基本上是垃圾邮件我创建的测试subreddit。而不是分享这些特定信息,这是一个显示我遇到的确切问题的例子:

#Define Key Words
##################################
#System Requirements Definitions
sysReq1 = ('system requirements' and '?')
sysReq2 = ('can' and ('handle' or 'play' or 'run') and ('netbook' or 'notebook' or 'pc' or 'mac' or 'macbook' or 'laptop' or 'comp' or 'computer') and '?')
#System Requirements Response
sysReqResponse = 'PROGRESS'
##################################
testString1 = "i hate this"
#intended result for 1: nothing
testString2 = "is that real?"
#intended result for 2: nothing
testString3 = "What are the system requirements?"
#intended result for 3: 'PROGRESS'
print testString1
if (sysReq1 or sysReq2) in testString1.lower():
    print sysReqResponse
print testString2
if (sysReq1 or sysReq2) in testString2.lower():
    print sysReqResponse
print testString3
if (sysReq1 or sysReq2) in testString2.lower():
print sysReqResponse

运行时,会显示:

i hate this
is that real?
PROGRESS
What are the system requirements?
PROGRESS

它不断返回testString2的值。我认为它与'?'有关但真的不知道如何或为什么或如何处理它。救命啊!

编辑:这是我想要显示的内容:

运行时,会显示:

i hate this
is that real?
What are the system requirements?
PROGRESS

到目前为止,我发现如果我将sysReq1 = ('system requirements' and '?')更改为sysReq1 = 'system requirements' '?'并仅检查if sysReq1,则会返回战斗值。问题是我真的需要那些or语句来减少混乱/冗余。

sysReq2存在的原因是因为有些人对同一个答案提出了不同的问题:

  • 可以在我的上网本上运行吗?

  • 我的电脑可以处理吗?

  • 我可以在我的Mac上播放吗?

这是排除'我能够'的变化,但你明白了。所有这些都应返回相同的值(在本例中为“PROGRESS”)

3 个答案:

答案 0 :(得分:1)

两个问题。首先,您不能使用andor“存储”某种比较运算符以供日后使用。当您编写andor时,会立即评估结果。 the documentation

中描述了相关规则

其次,您不能以and方式使用orinin不会“分发”andor。写('A' and 'B') in x并不意味着“x中的A和x中的B”。它首先评估('A' and 'B') (在这种情况下会给你'B'),然后检查单个结果是否在x

使用简单的运算符无法实现您的目标。没有办法只使用andor运算符来存储您可以稍后应用的复杂查询。您将不得不将标准转换为函数,并使用“测试字符串”作为参数调用它们:

def sysReq1(x):
    return 'system requirements' in x and '?' in x

>>> testString2 = "is that real?"
... testString3 = "What are the system requirements?"
... print testString2
... if sysReq1(testString2.lower()):
...     print "2 passed the test"
... print testString3
... if sysReq1(testString3.lower()):
...     print "3 passed the test"
is that real?
What are the system requirements?
3 passed the test

我建议你通过the Python tutorial来处理Python的基础知识。

答案 1 :(得分:1)

我认为anyallgenerators可以帮到你。

代码

#Define Key Words
##################################
#System Requirements Definitions
sysReq1 = ['system requirements', '?']
sysReq2 = [['can']
          ,['handle', 'play', 'run']
          ,['netbook', 'notebook', 'pc', 'mac', 'macbook', 'laptop', 'comp', 'computer']
          ,['?']
          ]
def test(testString):
    lowerTestString = testString.lower()
    return all(i in lowerTestString for i in sysReq1) or all(any(j in lowerTestString for j in i) for i in sysReq2)
#System Requirements Response
sysReqResponse = 'PROGRESS'
##################################
testString1 = "i hate this"
#intended result for 1: nothing
testString2 = "is that real?"
#intended result for 2: nothing
testString3 = "What are the system requirements?"
#intended result for 3: 'PROGRESS'
print testString1
if test(testString1):
    print sysReqResponse
print testString2
if test(testString2):
    print sysReqResponse
print testString3
if test(testString3):
    print sysReqResponse

该功能并非绝对必要,但它确实使代码更易于维护。如果您需要更改支票,它只会在一个地方更改。

这里发生了什么?

首先,我们将两组字符串转换为列表和列表列表。然后,要求变为“字符串必须包含sysReq1的所有元素或sysReq2的每个子列表中的至少一个元素。”

我们通过将生成器与anyall函数组合来完成检查此条件。在存储lower以避免重复调用它之后,我们创建了一个布尔值的生成器(相当于迭代器)。每个布尔告诉我们降低后是否包含sysReq1的单个元素。然后我们将这个迭代器传递给第一个all,它检查列表是否包含所有True个。如果是,则all函数返回True,第二次检查被短路。否则,它返回False并且Python移过or.

sysReq2的检查更复杂。首先,我们为每个子列表创建一个布尔生成器;这是在any电话中。此列表包含一组布尔值,表示子列表中的每个元素是否都在降低的字符串中。如果此布尔值列表中的任何元素(基于子列表)为any,则True调用将返回True。 (顺便说一下,它是短路的,因为我们使用的是生成器,所以True之后的检查甚至都没有运行,就像我们使用了一个列表一样。)然后我们创建另一个生成器;这个包含每个子列表测试的结果(所有any调用)。然后在此生成器上调用all,该生成器检查问题是否包含所有子列表中的元素。

我会注意到,如果用户直接输入,他们可以输入无意义的问题。例如,'Play can netbook kuguekf ugifugfj ugufsgjf nugjfgjfgj?'会通过此检查。

摘要

使用generator来运行返回布尔值的测试。使用anyall组合布尔值的可迭代。

修改

根据评论,这是一个替代解决方案split按空格输入字符串并使用set而不是list s。我还从您列出的示例问题中添加了一个测试用例,以确保or的第二部分被命中。

#Define Key Words
##################################
#System Requirements Definitions
sysReq1 = set(['system', 'requirements'])
sysReq2 = [set(['can'])
          ,set(['handle', 'play', 'run'])
          ,set(['netbook', 'notebook', 'pc', 'mac', 'macbook', 'laptop', 'comp', 'computer'])
          ]
def test(testString):
    if not testString.endswith('?'):
        return False

    lowerTestString = set(testString.rstrip('?').lower().split())
    return  lowerTestString.issuperset(sysReq1) or all(not lowerTestString.isdisjoint(i) for i in sysReq2)
#System Requirements Response
sysReqResponse = 'PROGRESS'
##################################
testString1 = "i hate this"
#intended result for 1: nothing
testString2 = "is that real?"
#intended result for 2: nothing
testString3 = "What are the system requirements?"
#intended result for 3: 'PROGRESS'
testString4 = "Can my PC handle it?"
#intended result for 4: 'PROGRESS'
print testString1
if test(testString1):
    print sysReqResponse
print testString2
if test(testString2):
    print sysReqResponse
print testString3
if test(testString3):
    print sysReqResponse
print testString4
if test(testString4):
    print sysReqResponse

我认为这是相当简单的。请注意,set构造函数采用可迭代的方式,因此我只是为此传递列表。 “不相交”部分可能有点令人困惑;它只是确保交叉点不是空的。我使用它希望函数被实现,以便它不计算整个交集。问号是有问题的,因为它没有被空格分隔,所以我只是确保字符串以问号结束并且rstrip将其关闭。

实际上,这个实现可能比具有大量生成器的实现更清晰,更易于维护。

答案 2 :(得分:0)

在python中,包含BOOLEAN OPERATORS的表达式的输出不必是BOOLEAN(http://docs.python.org/2/library/stdtypes.html) 例如,sysReq1 = ('system requirements' and '?')将生成sysReq1='?'并在此注意sysReq1不是布尔值,而是等于QUESTION MARK的字符串。同样,sysReq2也将等于?。此外,在上面的链接中查找TRUTH VALUE TESTING,因为这将解释哪些值将被视为FALSE表达式。