Removing phrases with re.sub with different letter cases in python

Viewed 43

I'm trying to remove some phrases out of a string not dependent on letter case, but there are some words/phrases ending with "&" that should remove everything including the word after the connected word/phrase.

import re

txt = "People have a different titles, like Dr. Mr. Miss and so on."
removed = "like", "Different titles,", "a", "Miss and&"
char = "&"


removed = list(sorted(removed))
for i in range(len(removed)):
    removed[i] = removed[i].upper()

txt = re.sub(fr"\s*(?<!\S)(?:{'|'.join(map(re.escape, removed))})(?!\S)", "", txt.upper()).strip()

This gives me "PEOPLE HAVE DR. MR. MISS AND SO ON.". Is there any way using regex to have the result as "PEOPLE HAVE DR. MR."? If not with regex then how to remove phrases from a string? At the moment I have tried it like this, unfortunately to no avail.

txt = "People have a different titles, like Dr. Mr. Miss and so on."
remove = "like", "a", "&Miss and", "&so"
ch = "&"
txt = txt.split()
new = []

for i in txt:
    if ch+i in remove:
        break
    else:
        if i not in remove:
            new.append(i)
result = " ".join(new)

I get the result "People have different titles, Dr. Mr. Miss and", whereas I would like to get "People have different titles, Dr. Mr."

1 Answers

You can use

import re
txt = "People have a different titles, like Dr. Mr. Miss and so on."
removed = "like", "Different titles,", "a", "Miss and&"
char = "&"
removed = list(sorted(removed))
p = fr"\s*\b(?:{'|'.join(map(re.escape, removed))})(?:(?<=\w)\b|(?<!\w))"
txt = re.sub(p.replace(f'\{char}', ".*"), "", txt, flags=re.I).strip().upper()
print(txt)

See the Python demo. Output:

PEOPLE HAVE DR. MR.

The p pattern will look like \s*\b(?:Different\ titles,|Miss\ and\&|a|like)(?:(?<=\w)\b|(?<!\w)), where the \s* matches zero or more whitespaces, a word boundary \b, several alternatives you passed as the removed list, and then a (?:(?<=\w)\b|(?<!\w)) adaptive right-hand word boundary (it will require a word boundary on the right of the words only if they end with a word char. More details in my "Dynamic adaptive word boundaries" YT video).

The .replace(f'\{char}', ".*") "converts" & to .* to match any text (any zero or more chars other than line break chars as many as possible).

The flags=re.I option makes matching case insensitive, no need to lower() or upper() the removed words.

Related