3

In Python, I'd like to test for the existence of a keyword in the output of a Linux command. The keywords to test for would be passed as a list as shown below. I've not spent a lot of time with Python so brute-force approach is below. Is there a cleaner way to write this?

def test_result (result, mykeys):

  hit = 0
  for keyword in mykeys:
     if keyword in result:
        hit = 1
        print "found a match for " + keyword

  if hit == 1:
     return True


result = "grep says awk"
mykeys = ['sed', 'foo', 'awk']
result = test_result (result, mykeys)
4
  • 4
    You might want to ask here codereview.stackexchange.com Commented Jun 5, 2018 at 15:25
  • Had no idea. That would be best. Thanks Commented Jun 5, 2018 at 15:28
  • 1
    do NOT use the identity operator (is) for equality testing. Your if hit is 1 test only seems to work because of an implementation detail in CPython, you want if hit == 1 Commented Jun 5, 2018 at 15:54
  • Agreed. I've fixed it in the question. Thanks for the catch. Commented Jun 8, 2018 at 20:56

4 Answers 4

4

The any built-in will do it.

def test_result(result, mykeys):
    return any(key in result for key in mykeys)
Sign up to request clarification or add additional context in comments.

Comments

2

You can use a regular expression to accomplish this. A regular expression of the form a|b|c matches any of a, b or c. So, you'd want something of the form:

import re
p = re.compile('|'.join(mykeys))
return bool(p.search(result))

p.search(result) searches the entire string for a match of the regular expression; it returns a match (which is truth-y) if present and returns None (which is false-y) otherwise. Converting the result to bool gives True if it matches and False otherwise.

Putting this together, you'd have:

import re

def test_result(result, mykeys):
  p = re.compile('|'.join(mykeys))
  return bool(p.search(result))

You can also make this more concise by not pre-compiling the regular expression; this should be fine if it's a one-time use:

def test_result(result, mykeys):
  return bool(re.search('|'.join(mykeys), result))

For reference, read about Python's re library.

2 Comments

I think this is a better approach, you can avoid those ifs easily with this method
'Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.'
2

Your function does two things, printing and returning the result. You could break them up like so:

def test_result(result, mykeys):
    return [k in result for k in mykeys]

def print_results(results):
    for result in results:
        print("found a match for " + result)

test_result will return a list with all the found keys, or an empty list. The empty list is falsey, so you can use it for whatever tests you want. The print_results is only needed if you actually want to print, otherwise you can use the result in some other function.

If you only want to check for the presence and don't care about which key you found, you can do something like:

def test_result(result, my_keys):
    return any(map(lambda k: k in result, mykeys))

If you're using python3 (as you should be), I believe this will be lazy and only evaluate as much of the list as necessary.

See A more concise way to write this Python code for a more concise version of this last function.

Comments

0

To search for an element in a list, you can use a for-else statement. In particular, this allows to return the found element.

def test_result (result, mykeys):
   for keyword in mykeys:
     if keyword in result: break
   else:
       return None
   return keyword

print(test_result("grep says awk", ['sed', 'foo', 'awk'])) # 'awk'
print(test_result("grep says awk", ['bar', 'foo'])) # None

Comments

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.