While the find() and count() string functions can check for string occurences, there is no function to check on the occurence of a set of characters.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def containsAny(str, set):
"""Check whether 'str' contains ANY of the chars in 'set'"""
return 1 in [c in str for c in set]
def containsAll(str, set):
"""Check whether 'str' contains ALL of the chars in 'set'"""
return 0 not in [c in str for c in set]
if __name__ == "__main__":
# unit tests, must print "OK!" when run
assert containsAny('*.py', '*?[]')
assert not containsAny('file.txt', '*?[]')
assert containsAll('43221', '123')
assert not containsAll('134', '123')
print "OK!"
|
While working on a condition to check whether a string contained the special characters used in the glob.glob() standard library function, I came up with the above code (with help from the OpenProjects IRC channel #python). Written this way, it really is compatible with human thinking, even though you might not come up with such code intuitively. That is often the case with list comprehensions.
"[c in str for c in set]" creates a list of true/false values, one for each char in the set. "1 in [c in str for c in set]" then checks if at least one "true" is in that list.
Similarly, "0 not in truthlist" checks that no "false" is in the list, i.e. that all conditions are true.
Neat idiom. A very neat idiom and a good illustration of the power of list comprehensions.
Another solution. It might be a neat idiom, but i prefer the following solution, because:
a) It reads almost as plain English and I think this is always more Pythonic :)
b) It is definitely more efficient. You can break out of the loop early via return after the first matching character is found (containsAny case) and after the first character in 'set' is found that is not contained in 'str' (containsAll case).