Regex find one or more character, including those with period or apostrophe or hypen in between. Without last symbol if it occur only once at end

Viewed 132
re.findall(r'[A-Za-z]+(?=\'|\.|\-[A-Za-z]+)?', txt) 
re.findall(r'[A-Za-z\.\-]+(?:\'[A-Za-z]+)?',txt)

Input

txt = "which would find I'm U.S. co-op, include ending. without the . , but not ' - . rd- "

expected_output

['which', 'would', 'find', "I'm", "U.S.", 'co-op', 'include', 'ending', 'without', 'the', 'but', 'not', 'rd']

I tried the above and variations, but can't get it to work. How to do it?

2 Answers

You may use this regex for matches using findall:

\w+(?:['.-]\w+\.?)?

RegEx Demo

RegEx Details:

  • \w+: Match 1+ word characters
  • (?:['.-]\w+\.?)?: Optional non-capturing group that starts with a ' or . or - followed by 1+ word characters and an optional trailing dot.

Code:

import re
txt = "which would find I'm U.S. co-op, include ending. without the . , but not ' - . rd- "
print (re.findall(r"\b\w+(?:['.-]\w+\.?)?", txt))

['which', 'would', 'find', "I'm", 'U.S.', 'co-op', 'include', 'ending', 'without', 'the', 'but', 'not', 'rd']

At risk of overthinking your actual issue, here is my attempt with the following assumptions:

  • You only want to use alphachars [A-Za-z].
  • You don't want to match trailing dots in cases like "let's play co-op.".
  • Lastly, my guess is you will also want to capture double hyphened words like "non-English-speaking" and abbreviations with more than just a single dot.

Thus, what I came up with is:

\b[a-z]+(?:(?:(\.)|['-])[a-z]+\1?)*

See an online demo.

  • \b - A word boundary.
  • [a-z]+ - 1+ alphachars.
  • (?: - Open 1st non-capture group:
    • (?: - Open 1nd non-capture group:
      • (\.)|['-] - A 1st capture group holding a dot or a hyphen or apostrophe.
      • )[a-z]+\1? - Close 2nd non-capture group, match 1+ alphachars and optionally match what is captured in the 1st capture group (thus a dot).
    • )* - Close 1st non-capture group and match 0+ times.

In Python, it could look like something like:

import re
txt = "which would find I'm U.S. co-op, include ending. without the . , but not ' - . rd- "
lst = [m.group(0) for m in re.finditer(r"\b[a-z]+(?:(?:(\.)|['-])[a-z]+\1?)*", txt, re.I)]
print(lst) # ['which', 'would', 'find', "I'm", 'U.S.', 'co-op', 'include', 'ending', 'without', 'the', 'but', 'not', 'rd']
Related