Regex to exclude optional words and return as list

Viewed 59

I am trying to extract the name and profession as a list of tuples from the below string using regex.

Input string

text = "Mr John,Carpenter,Mrs Liza,amazing painter"

As you can see the first word is the name followed by the profession which repeats in a comma seperated fashion. The problem is that, I want to get rid of the adjectives that comes along with the profession. For e.g "amazing" in the below example.

Expected output

 [('Mr John', 'Carpenter'), ('Mrs Liza', 'painter')]

I stripped out the adjective from the text using "replace" and used the below code using "regex" to get the output. But I am looking for a single regex function to avoid running the string replace. I figured that this has something to do with look ahead in regex but couldn't make it work. Any help would be appreciated.

 text.replace("amazing ", "")
 txt_new = re.findall("([\w\s]+),([\w\s]+)",text)
2 Answers

If you only want to use word and whitespace characters, this could be another option:

(\w+(?:\s+\w+)*)\s*,\s*(?:\w+\s+)*(\w+)

Explanation

  • ( Capture group 1
    • \w+(?:\s+\w+)* Match 1+ word chars and optionally repeat 1+ whitespace chars and 1+ word chars
  • ) Close group 1
  • \s*,\s* Match a comma between optional whitespace chars
  • (?:\w+\s+)* Optionally repeat 1+ word and 1+ whitespace chars
  • (\w+) Capture group 2, match 1+ word chars

Regex demo | Python demo

import re
 
regex = r"(\w+(?:\s+\w+)*)\s*,\s*(?:\w+\s+)*(\w+)"
s = ("Mr John,Carpenter,Mrs Liza,amazing painter")
print(re.findall(regex, s))

Output

[('Mr John', 'Carpenter'), ('Mrs Liza', 'painter')]

Here is one regex approach using re.findall:

text = "Mr John,Carpenter,Mrs Liza,amazing painter"
matches = re.findall(r'\s*([^,]+?)\s*,\s*.*?(\S+)\s*(?![^,])', text)
print(matches)

This prints:

[('Mr John', 'Carpenter'), ('Mrs Liza', 'painter')]

Here is an explanation of the regex pattern:

\s*        match optional whitespace
([^,]+?)   match the name
\s*        optional whitespace
,          first comma
\s*        optional whitespace
.*?        consume all content up until
(\S+)      the last profession word
\s*        optional whitespace
(?![^,])   assert that what follows is either comma or the end of the input
Related