You can use the word-boundaries of regular expressions. Example:
import re
s = '98787This is correct'
for words in ['This is correct', 'This', 'is', 'correct']:
if re.search(r'\b' + words + r'\b', s):
print('{0} found'.format(words))
That yields:
is found
correct found
For an exact match, replace \b assertions with ^ and $ to restrict the match to the begin and end of line.
You can use the word-boundaries of regular expressions. Example:
import re
s = '98787This is correct'
for words in ['This is correct', 'This', 'is', 'correct']:
if re.search(r'\b' + words + r'\b', s):
print('{0} found'.format(words))
That yields:
is found
correct found
For an exact match, replace \b assertions with ^ and $ to restrict the match to the begin and end of line.
Use the comparison operator == instead of in then:
if text == 'This is correct':
print("Correct")
This will check to see if the whole string is just 'This is correct'. If it isn't, it will be False
python - finding an exact match for string - Stack Overflow
python - Find exact match in list of strings - Stack Overflow
How to use str.contains to get exact matches and not partial ones?
loops - Python string search: how to find exact matches, and not match with strings that contain searched string in them - Stack Overflow
Goal:
-
I'd like to find all exact occurrences of a string, or close matches of it, in a longer string in Python.
-
I'd also like to know the location of these occurrences in the longer string.
-
To define what a close match is, I'd like to set a threshold, e.g. number of edits if using the edit distance as the metric.
-
I'd also like the code to give a matching score (the one that is likely used to determine if a candidate substring is over the matching threshold I set).
How can I do so in Python?
Example:
long_string = """1. Bob likes classical music very much. 2. This is classic music! 3. This is a classic musical. It has a lot of classical musics. """ query_string = "classical music"
I'd like the Python code to find "classical music" and possibly "classic music", "classic musical" and "classical musics" depending on the string matching threshold I set.
Research: I found Checking fuzzy/approximate substring existing in a longer string, in Python? but the question focuses on the best match only (i.e., not all occurrences) and answers either also focuses on the best match or don't work on multi-word query strings (since the question only had a single-word query strings, or return some incorrect score (doesn't get a perfect score even for an exact match).
Make your own word-boundary:
def exact_Match(phrase, word):
b = r'(\s|^|$)'
res = re.match(b + word + b, phrase, flags=re.IGNORECASE)
return bool(res)
copy-paste from here to my interpreter:
>>> str1 = "award-winning blueberries"
>>> word1 = "award"
>>> word2 = "award-winning"
>>> exact_Match(str1, word1)
False
>>> exact_Match(str1, word2)
True
Actually, the casting to bool is unnecessary and not helping at all. The function is better off without it:
def exact_Match(phrase, word):
b = r'(\s|^|$)'
return re.match(b + word + b, phrase, flags=re.IGNORECASE)
note: exact_Match is pretty unconventional casing. just call it exact_match.
The problem with your initial method is that '\\b' does not denote the zero-width assertion search that your looking for. (And if it did, I would use r'\b' instead because backslashes can become a real hassle in regular expressions - see this link)
From Regular Expression HOWTO
\b
Word boundary. This is a zero-width assertion that matches only at the beginning or end of a word. A word is defined as a sequence of alphanumeric characters, so the end of a word is indicated by whitespace or a non-alphanumeric character.
Because - is a non-alphanumeric character, your findall regular expression will find award in award-wining but not in awards.
Depending on your searched phrase, I would also think of using re.findall instead of re.match as suggested by Elazar. In your example re.match works, but if the word you are looking for is nested anywhere beyond the beginning of the string, re.match will not succeed.
Using a set would be much faster than iterating through the lists.
checklist = ['A', 'FOO']
words = ['fAr', 'near', 'A']
matches = set(checklist).intersection(set(words))
print(matches) # {'A'}
This will get you a list of exact matches.
matches = [c for c in checklist if c in words]
Which is the same as:
matches = []
for c in checklist:
if c in words:
matches.append(c)
Hi, I don't get why when I use str.contains to get exact matches from a list of keywords, the output still contains partial matches. Here is an extract of what I have (I'm only including one keyword in the list for the example):
keyword= ['SE.TER.ENRL']
subset = df[df['Code'].str.contains('|'.join(keyword), case=False, na=False)]
Output: ['SE.TER.ENRL' 'SE.TER.ENRL.FE' 'SE.TER.ENRL.FE.ZS']
Does anyone know how to get around this?
Thanks!
For this kind of thing, regexps are very useful :
import re
print(re.findall('\\blocal\\b', "Hello, locally local test local."))
// ['local', 'local']
\b means word boundary, basically. Can be space, punctuation, etc.
Edit for comment :
print(re.sub('\\blocal\\b', '*****', "Hello, LOCAL locally local test local.", flags=re.IGNORECASE))
// Hello, ***** locally ***** test *****.
You can remove flags=re.IGNORECASE if you don't want to ignore the case, obviously.
Below you can use simple function.
def find_word(text, search):
result = re.findall('\\b'+search+'\\b', text, flags=re.IGNORECASE)
if len(result)>0:
return True
else:
return False
Using:
text = "Hello, LOCAL locally local test local."
search = "local"
if find_word(text, search):
print "i Got it..."
else:
print ":("
This should work, no matter how long your list is and how you sort things:
def find_str(row, list_):
words = row.split(' ')
for elem in words:
for search_str in list_:
if search_str in elem:
return elem
return row
df['Exact_match'] = df['Product'].apply(find_str, list_=my_list)
Re-order the searches so that it's longest string first and also use .str.extract instead of an applied function, eg:
df['Product'].str.extract('(Clarins|Lysol|Lys|Cla)')
Maybe you could use match to check for the same
df_return = df[df['columnA'].str.match(pat='(perfect)|(this dentist is great)')]
df_return
Please let me know if this helps!
Use straight equal check == instead of contains something like
if df["columnA"].str == 'perfect' or df["columnA"].str == 'this dentist is great':
print(["columnA"].str)
or
if df["columnA"].str in {'perfect', 'this dentist is great'}:
print(["columnA"].str)
A regex of the form r"(abc|ef|xxx)" will match with "abc", "ef", or "xxx". You can create this regex by using the string concatenation as below.
Note re.search returns None if no match is found.
import re
phrases = ['hello', 'hi', 'bye']
def match(text):
r = re.search(r'\b({})\b'.format("|".join(phrases)), text)
return r is not None
match("hi there, how are you?"), match("hithere, how are you?")
# (True, False)
One possible solution is to first split() the sentence into words, then strip() any punctuation marks and alike for each word and finally check if that word matches a word in the list. Actually you should not use a list but a Set which will enable lookups in constant (O(1)) time instead of linear (O(n)) time as is the case with lists.
phrases = ['hello', 'hi', 'bye']
phraseSet = set(phrases)
def match(text: str, word_set: set[str]) -> bool:
words = text.split(" ")
for word in words:
stripped = word.strip(".?!,:")
if stripped in word_set:
return True
return False
print(match("hi there, how are you?", phraseSet))
print(match("hithere, how are you?", phraseSet))
Obviously one could write the above solution in a more pythonic way.
You could try searching for sample_8_1/ (i.e., include the following slash). I guess given your code that would be dire.find(name+'/'). This just a quick and dirty approach.
Assuming that dire is populated with absolute path names
for name in sample_names:
if name in dire:
...
e.g.
samples = ['/home/msvalkon/work/tmp_1',
'/home/msvalkon/work/tmp_11']
dirs = ['/home/msvalkon/work/tmp_11']
for name in samples:
if name in dirs:
print "Entry %s matches" % name
Entry /home/msvalkon/work/tmp_11 matches