if any(word in 'some one long two phrase three' for word in list_):
Answer from kennytm on Stack Overflowif any(word in 'some one long two phrase three' for word in list_):
Here are a couple of alternative ways of doing it, that may be faster or more suitable than KennyTM's answer, depending on the context.
1) use a regular expression:
import re
words_re = re.compile("|".join(list_of_words))
if words_re.search('some one long two phrase three'):
# do logic you want to perform
2) You could use sets if you want to match whole words, e.g. you do not want to find the word "the" in the phrase "them theorems are theoretical":
word_set = set(list_of_words)
phrase_set = set('some one long two phrase three'.split())
if word_set.intersection(phrase_set):
# do stuff
Of course you can also do whole word matches with regex using the "\b" token.
The performance of these and Kenny's solution are going to depend on several factors, such as how long the word list and phrase string are, and how often they change. If performance is not an issue then go for the simplest, which is probably Kenny's.
Help!: Check if a Python list item contains a string inside another string but with conditions
Check if a word is in a string in Python - Stack Overflow
python - How do I check if words in a string are elements in a list or lists? - Stack Overflow
Python check if string contains words from specific list of strings - Stack Overflow
This function was found by Peter Gibson (below) to be the most performant of the answers here. It is good for datasets one may hold in memory (because it creates a list of words from the string to be searched and then a set of those words):
def words_in_string(word_list, a_string):
return set(word_list).intersection(a_string.split())
Usage:
my_word_list = ['one', 'two', 'three']
a_string = 'one two three'
if words_in_string(my_word_list, a_string):
print('One or more words found!')
Which prints One or words found! to stdout.
It does return the actual words found:
for word in words_in_string(my_word_list, a_string):
print(word)
Prints out:
three
two
one
For data so large you can't hold it in memory, the solution given in this answer would be very performant.
To satisfy my own curiosity, I've timed the posted solutions. Here are the results:
TESTING: words_in_str_peter_gibson 0.207071995735
TESTING: words_in_str_devnull 0.55300579071
TESTING: words_in_str_perreal 0.159866499901
TESTING: words_in_str_mie Test #1 invalid result: None
TESTING: words_in_str_adsmith 0.11831510067
TESTING: words_in_str_gnibbler 0.175446796417
TESTING: words_in_string_aaron_hall 0.0834425926208
TESTING: words_in_string_aaron_hall2 0.0266295194626
TESTING: words_in_str_john_pirie <does not complete>
Interestingly @AaronHall's solution
def words_in_string(word_list, a_string):
return set(a_list).intersection(a_string.split())
which is the fastest, is also one of the shortest! Note it doesn't handle punctuation next to words, but it's not clear from the question whether that is a requirement. This solution was also suggested by @MIE and @user3.
I didn't look very long at why two of the solutions did not work. Apologies if this is my mistake. Here is the code for the tests, comments & corrections are welcome
from __future__ import print_function
import re
import string
import random
words = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten']
def random_words(length):
letters = ''.join(set(string.ascii_lowercase) - set(''.join(words))) + ' '
return ''.join(random.choice(letters) for i in range(int(length)))
LENGTH = 400000
RANDOM_STR = random_words(LENGTH/100) * 100
TESTS = (
(RANDOM_STR + ' one two three', (
['one', 'two', 'three'],
set(['one', 'two', 'three']),
False,
[True] * 3 + [False] * 7,
{'one': True, 'two': True, 'three': True, 'four': False, 'five': False, 'six': False,
'seven': False, 'eight': False, 'nine': False, 'ten':False}
)),
(RANDOM_STR + ' one two three four five six seven eight nine ten', (
['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten'],
set(['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten']),
True,
[True] * 10,
{'one': True, 'two': True, 'three': True, 'four': True, 'five': True, 'six': True,
'seven': True, 'eight': True, 'nine': True, 'ten':True}
)),
('one two three ' + RANDOM_STR, (
['one', 'two', 'three'],
set(['one', 'two', 'three']),
False,
[True] * 3 + [False] * 7,
{'one': True, 'two': True, 'three': True, 'four': False, 'five': False, 'six': False,
'seven': False, 'eight': False, 'nine': False, 'ten':False}
)),
(RANDOM_STR, (
[],
set(),
False,
[False] * 10,
{'one': False, 'two': False, 'three': False, 'four': False, 'five': False, 'six': False,
'seven': False, 'eight': False, 'nine': False, 'ten':False}
)),
(RANDOM_STR + ' one two three ' + RANDOM_STR, (
['one', 'two', 'three'],
set(['one', 'two', 'three']),
False,
[True] * 3 + [False] * 7,
{'one': True, 'two': True, 'three': True, 'four': False, 'five': False, 'six': False,
'seven': False, 'eight': False, 'nine': False, 'ten':False}
)),
('one ' + RANDOM_STR + ' two ' + RANDOM_STR + ' three', (
['one', 'two', 'three'],
set(['one', 'two', 'three']),
False,
[True] * 3 + [False] * 7,
{'one': True, 'two': True, 'three': True, 'four': False, 'five': False, 'six': False,
'seven': False, 'eight': False, 'nine': False, 'ten':False}
)),
('one ' + RANDOM_STR + ' two ' + RANDOM_STR + ' threesome', (
['one', 'two'],
set(['one', 'two']),
False,
[True] * 2 + [False] * 8,
{'one': True, 'two': True, 'three': False, 'four': False, 'five': False, 'six': False,
'seven': False, 'eight': False, 'nine': False, 'ten':False}
)),
)
def words_in_str_peter_gibson(words, s):
words = words[:]
found = []
for match in re.finditer('\w+', s):
word = match.group()
if word in words:
found.append(word)
words.remove(word)
if len(words) == 0: break
return found
def words_in_str_devnull(word_list, inp_str1):
return dict((word, bool(re.search(r'\b{}\b'.format(re.escape(word)), inp_str1))) for word in word_list)
def words_in_str_perreal(wl, s):
i, swl, strwords = 0, sorted(wl), sorted(s.split())
for w in swl:
while strwords[i] < w:
i += 1
if i >= len(strwords): return False
if w != strwords[i]: return False
return True
def words_in_str_mie(search_list, string):
lower_string=string.lower()
if ' ' in lower_string:
result=filter(lambda x:' '+x.lower()+' ' in lower_string,search_list)
substr=lower_string[:lower_string.find(' ')]
if substr in search_list and substr not in result:
result+=substr
substr=lower_string[lower_string.rfind(' ')+1:]
if substr in search_list and substr not in result:
result+=substr
else:
if lower_string in search_list:
result=[lower_string]
def words_in_str_john_pirie(word_list, to_be_searched):
for word in word_list:
found = False
while not found:
offset = 0
# Regex is expensive; use find
index = to_be_searched.find(word, offset)
if index < 0:
# Not found
break
if index > 0 and to_be_searched[index - 1] != " ":
# Found, but substring of a larger word; search rest of string beyond
offset = index + len(word)
continue
if index + len(word) < len(to_be_searched) \
and to_be_searched[index + len(word)] != " ":
# Found, but substring of larger word; search rest of string beyond
offset = index + len(word)
continue
# Found exact word match
found = True
return found
def words_in_str_gnibbler(words, string_to_be_searched):
word_set = set(words)
found = []
for match in re.finditer(r"\w+", string_to_be_searched):
w = match.group()
if w in word_set:
word_set.remove(w)
found.append(w)
return found
def words_in_str_adsmith(search_list, big_long_string):
counter = 0
for word in big_long_string.split(" "):
if word in search_list: counter += 1
if counter == len(search_list): return True
return False
def words_in_string_aaron_hall(word_list, a_string):
def words_in_string(word_list, a_string):
'''return iterator of words in string as they are found'''
word_set = set(word_list)
pattern = r'\b({0})\b'.format('|'.join(word_list))
for found_word in re.finditer(pattern, a_string):
word = found_word.group(0)
if word in word_set:
word_set.discard(word)
yield word
if not word_set:
raise StopIteration
return list(words_in_string(word_list, a_string))
def words_in_string_aaron_hall2(word_list, a_string):
return set(word_list).intersection(a_string.split())
ALGORITHMS = (
words_in_str_peter_gibson,
words_in_str_devnull,
words_in_str_perreal,
words_in_str_mie,
words_in_str_adsmith,
words_in_str_gnibbler,
words_in_string_aaron_hall,
words_in_string_aaron_hall2,
words_in_str_john_pirie,
)
def test(alg):
for i, (s, possible_results) in enumerate(TESTS):
result = alg(words, s)
assert result in possible_results, \
'Test #%d invalid result: %s ' % (i+1, repr(result))
COUNT = 10
if __name__ == '__main__':
import timeit
for alg in ALGORITHMS:
print('TESTING:', alg.__name__, end='\t\t')
try:
print(timeit.timeit(lambda: test(alg), number=COUNT)/COUNT)
except Exception as e:
print(e)
I have two days learning python but I really need to do that code. I also posted this question in StackOverflow but it got downvoted the first second.
I want to make a function to print all the words that contain a specific consonant (only one) and any amount of vowels, but I don't know how to introduce the conditions here.
I made a list with 4 elements via the input method (I know I use a different way), and a method that prints all the words that include the letter "f", but as I said, it needs to be more specific (only one consonant, "f" in this case, and any amount of vowels):
list = []
for x in range (4):
words = str(input("Type a word "))
list.append(words)
#This method kinda works, but it needs to be more specific.
matching = [s for s in list if "f" in s]
print(matching) In my code, if I have words with the letter "f", I'll get a list with all the words containing any amount of "f" letters and any other consonant, but I just want one consonant "f" and vowels, not the other consonants.
My desired result is like
list = [fox, alfa, fa, real, fou]
#['fa', 'fou']
What is wrong with:
if word in mystring:
print('success')
if 'seek' in 'those who seek shall find':
print('Success!')
but keep in mind that this matches a sequence of characters, not necessarily a whole word - for example, 'word' in 'swordsmith' is True. If you only want to match whole words, you ought to use regular expressions:
import re
def findWholeWord(w):
return re.compile(r'\b({0})\b'.format(w), flags=re.IGNORECASE).search
findWholeWord('seek')('those who seek shall find') # -> <match object>
findWholeWord('word')('swordsmith') # -> None
To check every element in list2 you have to loop over every element of that list. For each of those elements you have to check if it is a part of any element in list1.
for line in list2:
if any(value in line for value in list1):
print(line)
If you want to check if a string i contains string j, you can do it using i in j. Then comes the part how do you want the output actually. What my approach was to go through the list1 and for each of them go though the list2 and check if element of list2 contains the element of list1. If contains then i checked if they are equal or not. If equal i skipped them. Otherwise i have printed the element of list2.
As @mathius indicated, my code will print the same element of list2 more than once. I didn't handle that because to me, post maker didn't want that. Look forward to your opinion. Here is my code:
for i in list1:
for j in list2:
if i in j and i != j:
print j
Issues
Your for-loop iterates over each character in the message. So it has 176 iterations, each checking if character is list (! probably not what you want): if i == words
Solution
Other than answered by Riccardo with the elegant and concise but advanced construct of list-comprehension you could also fix your loop:
(A) You can either just turn your search around if word in message.
(B) Alternatively first split the message to chunks (words), e.g. by whitespace as delimiter. Then iterate over each of those chunks and test if in your list.
words = ["Lorem", "facilisis", "consectetur", "iaculis", "dolor"]
message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " \
"Aliquam aliquet facilisis orci, scelerisque iaculis odio dignissim nec. " \
"Vestibulum luctus erat sit amet suscipit commodo"
# (A) in approach
for w in words:
if w in message:
print(f"(A) Word found: {w}")
# (B) split approach
for chunk in message.split():
if chunk in words:
print(f"(B) Word found: {chunk}")
Prints a different ordered but same set of 5 words for each approach:
(A) Word found: Lorem
(A) Word found: facilisis
(A) Word found: consectetur
(A) Word found: iaculis
(A) Word found: dolor
(B) Word found: Lorem
(B) Word found: dolor
(B) Word found: consectetur
(B) Word found: facilisis
(B) Word found: iaculis
Note: the default separator when invoking str.split() without arguments is a whitespace (space, tab, new-line, etc.).
Bonus: improved splitting
To not only split on a single separator character or default whitespace use the string constants like:
string.whitespace, or regex equivalent shorthand\sstring.punctuation
in combination with re.split (split by regular-expression)
you can even improve your split and find words next to a line-break like 'Vestibulum' or words next to a punctuation-mark like ['amet', 'elit', 'orci', 'nec']:
message = "\tLorem ipsum dolor sit amet, consectetur adipiscing elit. " \
"Aliquam aliquet facilisis orci, scelerisque iaculis odio dignissim nec.\n" \
"Vestibulum luctus erat sit amet suscipit commodo"
words = ['amet', 'elit', 'orci', 'nec', 'Vestibulum']
import string
import re
sep_regex = '['+string.punctuation+'\s]' # use \s instead string.whitespace
chunks = re.split(sep_regex, message)
found_words = [w for w in chunks if w in words]
print(found_words)
Prints:
['amet', 'elit', 'orci', 'nec', 'Vestibulum', 'amet']
Note: It contains 'amet' twice because it was found twice. To get only the unique words found convert it to a set using set(found_words)
See also:
- Regex to split words in Python
- https://codereview.stackexchange.com/questions/230126/string-operation-to-split-on-punctuation
Try this:
words_found = [word for word in words if word in message]
Swear = ["curse", "curse", "curse"]
for i in Swear:
if i in Userinput:
print 'Quit Cursing!'
You should read up on the differences between lists and tuples.
You can use sets, if only you want to check the existance of swear words,
a_swear_set = set(Swear)
if a_swear_set & set(Userinput.split()):
print("Quit Cursing!")
else:
print("That sounds great!")
I didn't see it at first, but there's a very similar way to do this without doing it one letter a time. At each recursion, check if you can remove an entire word at a time off the front of the string, and then just keep going. In an initial test or two, it appears to run a good bit faster.
I think this is the first time I've used the count argument to str.replace.
def word_break(word_list, text):
text = text.replace(' ', '')
if text == '':
return True
return any(
text.startswith(word)
and word_break(word_list, text.replace(word, '', 1))
for word in word_list
)
If you're using Python 3.9+, you can replace text.replace(word, '', 1) with text.removeprefix(word).
I believe it's the same asymptotic complexity, but with a smaller constant (unless the words in your allowed list are all single characters, anyway).
I think the best way to go about this is to use a for-loop in this way:
def wordBreak(wordList, word):
word = word.replace(" ", "")
if word == "":
return True
#No need for an else statement
llist = []
words = []
for i in range(len(word)):
llist.append(word[i])
for j in range(len(llist)):
if i != j:
llist[j] += word[i]
if llist[j] in wordList:
#print(llist[j])
words.append(llist[j])
return words
wordList = ["the", "quick", "fox", "brown"]
word = "the quick brown fox"
print(wordBreak(wordList,word))
Although it is a bit lengthier than your original one, it runs much quicker.
It would be more Pythonic to use any() with a chained list comprehension:
print any(word in sublist for word in testtt.split() for sublist in allStrings)
However this will just return true/false; it won't identify which word was found in which sublist. You can print the specific matches with this list comprehension:
print [(word,sublist) for word in testtt.split() for sublist in allStrings if word in sublist]
Your code is a bit wasteful by calculating testtt.split() more than once.
What I can get is by use of chain and any:
resultStrings = [
"results:",
"result:",
"experimental:",
"experiments:",
"experiment:",
"results",
"result",
"experimental",
"experiments",
"experiment",
]
conclusionStrings = [
"conclusion:",
"conclusions:",
"concluding:",
"conclusion",
"conclusions",
"concluding",
]
allStrings = [resultStrings, conclusionStrings]
testtt = "this may thod be in techniques ever material and methods"
from itertools import chain
string_set = set(chain(*allStrings))
any(i in string_set for i in testtt.split())
Though set need some space, it can improve efficiency. Thanks Peter Wood.
Here's how I would do it:
allowed_words = set(['ABC','CDE','EFG'])
target_string = 'EFG EFG CDE'
print(all(word in allowed_words for word in target_string.split()))
Rather than trying to build every possible permutation and then checking (which will be unbounded if the input is unbounded), just do the search yourself.
The problem is 'check every component part of the string is present in an iterable' where component part is defined as 'part separated by a space':
def check_string_made_of_parts(candidate, parts):
return all(part in parts for part in candidate.split(" "))
With these kind of problems in python it's helpful to talk through a sensible algorithm in words before you hit any code.