2

I have a list of query terms, each with a boolean operator associated with them, like, say:

tom OR jerry OR desperate AND dan OR mickey AND mouse

Okay, now I have a string containing user-defined input, inputStr.

My question is, in Python, is there a way to determine if the string defined by the user contains the words in the "query"?

I have tried this:

if ('tom' or 'jerry' or 'desperate' and 'dan' or 'mickey' and 'mouse') in "cartoon dan character desperate":
    print "in string"

But it doesn't give the output i expect. As you can see, I don't care about whether the query terms are ordered; just whether they are in the string or not.

Can this be done? Am I missing something like a library which can help me achieve the required functionality?

Many thanks for any help.

2
  • The reason yours didn't work is because the and/or operators are boolean. Your expression boils down to `if True in "cartoon..": Commented Oct 16, 2011 at 16:57
  • Yup, I realise that one now. Having a look round the Internet for something that might work... Commented Oct 16, 2011 at 17:02

3 Answers 3

2

To check whether any of the words in a list are in the string:

any(word in string for word in lst)

Example:

# construct list from the query by removing 'OR', 'AND'
query = "tom OR jerry OR desperate AND dan OR mickey AND mouse"
lst = [term for term in query.split() if term not in ["OR", "AND"]]

string = "cartoon dan character desperate"
print any(word in string for word in lst)

If you use re.search() as @jro suggested then don't forget to escape words to avoid collisions with the regex syntax:

import re
m = re.search("|".join(map(re.escape, lst)), string)
if m:
   print "some word from the list is in the string"

The above code assumes that query has no meaning other than the words it contains. If it does then assuming that 'AND' binds stronger than 'OR' i.e., 'a or b and c' means 'a or (b and c)' you could check whether a string satisfies query:

def query_in_string(query, string):
    for term in query.split('OR'):
        lst = map(str.strip, term.split('AND'))
        if all(word in string for word in lst):
           return True
    return False

The above could be written more concisely but it might be less readable:

def query_in_string(query, string):
    return any(all(word.strip() in string for word in term.split('AND'))
               for term in query.split('OR'))

Example

query = "tom OR jerry AND dan"
print query_in_string(query, "cartoon jerry")   # -> False no dan or tom
print query_in_string(query, "tom is happy")    # -> True tom
print query_in_string(query, "dan likes jerry") # -> True jerry and dan

If you want to reject partial matches e.g., 'dan' should not match 'danial' then instead of word in string you could use re.search() and add '\b':

re.search(r"\b%s\b" % re.escape(word), string)
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your brilliant post. :) Superb! :D
1

I would use a regular expression:

>>> import re
>>> s = "cartoon dan character desperate"
>>> l = ['dan', 'mickey', 'mouse']
>>> print re.search('(%s)' % '|'.join(l), s)
<_sre.SRE_Match object at 0x0233AA60>
>>> l = ['nothing']
>>> print re.search('(%s)' % '|'.join(l), s)
None

Where s is the string to search in and l is a list of words that should be in s. If the search function doesn't return None, you have a match.

Comments

0
if ('tom' or 'jerry' or 'desperate' and 'dan' or 'mickey' and 'mouse') in "cartoon dan character desperate"

does not mean what you think it means, because the parentheses cause the or and and operations to be evaluated first, e.g:

>>> "tom" or "jerry" or "desperate" and "dan" or "mickey" and "mouse"
'tom'

... so your if-clause really means if 'tom' in "cartoon dan character desperate".

What you probably meant was something like:

if ('tom' in inputStr) or ('jerry' in inputStr) or ('desperate' in inputStr and 'dan' in inputStr) or ('mickey' in inputStr and 'mouse' in inputStr)

1 Comment

Can't believe I didn't think of that. Thank you, Kimvais -- thank you so much. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.