A word starting with t but ends with other than e

Viewed 175

I am trying to create a regex that starts with t or T and doesn't end with e letter. I tried the code below so far, but it's not giving me the desirable result. Could anyone show me what is exactly missing here?

my_str = my_file.read()

word = re.findall("[tT].*[^e]$", my_str)

print(word)
3 Answers

You can use

\bt(?:[a-z]*[a-df-z])?\b
\bt[a-z]*\b(?<!e)

Just for completeness, here is a regex to match any word starting with a Cyrillic т and not ending with a Cyrillic е:

\bт[^\W\d_]*\b(?<!е)

See the regex demo #1, regex demo #2 and a Cyrillic regex demo.

If you need a case insensitive matching, add re.I:

re.findall(r'\bt(?:[a-z]*[a-df-z])?\b', text, re.I)

And a note on word boundaries: if the words can be glued to _ or digits, use letter boundaries rather than word boundaries:

r'(?<![a-z])t(?:[a-z]*[a-df-z])?(?![a-z])'
r'(?<![^\W\d_])т[^\W\d_]*(?![^\W\d_])(?<!е)' # Unicode letter boundaries

Regex details

  • \b - word boundary (start of string or a position immediately after a char other than a digit, letter, underscore)
  • (?<![a-z]) ((?<![^\W\d_]) is a Unicode aware equivalent) - a negative lookbehind that matches a location that is not immediately preceded with a letter
  • t - a t letter
  • (?:[a-z]*[a-df-z])? - an optional non-capturing group matching 0 or more letters and then a letter other than e
  • \b - word boundary
  • (?![a-z]) ((?![^\W\d_]) is a Unicode aware equivalent) - a negative lookahead that matches a location that is not immediately followed with a letter.

Also,

  • \bt[a-z]*\b(?<!e) matches a word boundary, t, any zero or more lowercase ASCII letters (any ASCII letters with re.I), then a word boundary marks the end of a word and the negative lookbehind (?<!e) fails the match if there is e at the end of the word
  • [^\W\d_]* - matches zero or more more Unicode letters.

See a Python demo:

import re
text = r't, train => main,teene!'
cyr_text = r'таня  тане  работе'
print( re.findall(r'\bt(?:[a-z]*[a-df-z])?\b', text, re.I) )
# => ['t', 'train']
print( re.findall(r'\bt[a-z]*\b(?<!e)', text, re.I) )
# => ['t', 'train']
print( re.findall(r'\bт[^\W\d_]*\b(?<!е)', cyr_text, re.I) )
# => ['таня']
print( re.findall(r'(?<![^\W\d_])т[^\W\d_]*(?![^\W\d_])(?<!е)', cyr_text, re.I) )
# => ['таня']

Maybe:

[\W]([Tt]\w*[^e])[\W]

Any non word character followed by (capture: Tt, some optional word characters, not e) followed by first non word character

There is also another way of doing it:

re.findall(r"\b[Tt]+[a-zA-Z]*[^Ee\s]\b", my_str)
Related