Regex for extracting name starting with Mr.|Mrs - python

I was trying to write regex for identifying name starting with
Mr.|Mrs.
for example
Mr. A, Mrs. B.
I tried several expressions. These regular expressions were checked on online tool at pythonregex.com. The test string used is:
"hey where is Mr A how are u Mrs. B tt`"
Outputs mentioned are of findall() function of Python, i.e.
regex.findall(string)
Their respective outputs with regex are below.
Mr.|Mrs. [a-zA-Z]+ o/p-[u'Mr ', u'Mrs']
why A and B are not appearing with Mr. and Mrs.?
[Mr.|Mrs.]+ [a-zA-Z]+ o/p-[u's Mr', u'. B']
Why s is coming with Mr. instead of A?
I tried many more combinations but these are confusing so here are they. For name part I know regex has to cover more conditions but was starting from basic.

Change your regex like below,
(?:Mr\.|Mrs\.) [a-zA-Z]+
DEMO
You need to put Mr\., Mrs\. inside a non-capturing or capturing group , so that the | (OR) applies to the group itself.
You must need to escape the dot in your regex to match a literal dot or otherwise, it would match any character. . is a special meta character in regex which matches any character except line breaks.
OR
Even shorter one,
Mrs?\. [a-zA-Z]+
? quantifier in the above makes the previous character s as an optional one.

There's a python library for parsing human names :
https://github.com/derek73/python-nameparser
Much better than writing your own regex.

Related

Prevent last duplicate character from string [duplicate]

My regex pattern looks something like
<xxxx location="file path/level1/level2" xxxx some="xxx">
I am only interested in the part in quotes assigned to location. Shouldn't it be as easy as below without the greedy switch?
/.*location="(.*)".*/
Does not seem to work.
You need to make your regular expression lazy/non-greedy, because by default, "(.*)" will match all of "file path/level1/level2" xxx some="xxx".
Instead you can make your dot-star non-greedy, which will make it match as few characters as possible:
/location="(.*?)"/
Adding a ? on a quantifier (?, * or +) makes it non-greedy.
Note: this is only available in regex engines which implement the Perl 5 extensions (Java, Ruby, Python, etc) but not in "traditional" regex engines (including Awk, sed, grep without -P, etc.).
location="(.*)" will match from the " after location= until the " after some="xxx unless you make it non-greedy.
So you either need .*? (i.e. make it non-greedy by adding ?) or better replace .* with [^"]*.
[^"] Matches any character except for a " <quotation-mark>
More generic: [^abc] - Matches any character except for an a, b or c
How about
.*location="([^"]*)".*
This avoids the unlimited search with .* and will match exactly to the first quote.
Use non-greedy matching, if your engine supports it. Add the ? inside the capture.
/location="(.*?)"/
Use of Lazy quantifiers ? with no global flag is the answer.
Eg,
If you had global flag /g then, it would have matched all the lowest length matches as below.
Here's another way.
Here's the one you want. This is lazy [\s\S]*?
The first item:
[\s\S]*?(?:location="[^"]*")[\s\S]* Replace with: $1
Explaination: https://regex101.com/r/ZcqcUm/2
For completeness, this gets the last one. This is greedy [\s\S]*
The last item:[\s\S]*(?:location="([^"]*)")[\s\S]*
Replace with: $1
Explaination: https://regex101.com/r/LXSPDp/3
There's only 1 difference between these two regular expressions and that is the ?
The other answers here fail to spell out a full solution for regex versions which don't support non-greedy matching. The greedy quantifiers (.*?, .+? etc) are a Perl 5 extension which isn't supported in traditional regular expressions.
If your stopping condition is a single character, the solution is easy; instead of
a(.*?)b
you can match
a[^ab]*b
i.e specify a character class which excludes the starting and ending delimiiters.
In the more general case, you can painstakingly construct an expression like
start(|[^e]|e(|[^n]|n(|[^d])))end
to capture a match between start and the first occurrence of end. Notice how the subexpression with nested parentheses spells out a number of alternatives which between them allow e only if it isn't followed by nd and so forth, and also take care to cover the empty string as one alternative which doesn't match whatever is disallowed at that particular point.
Of course, the correct approach in most cases is to use a proper parser for the format you are trying to parse, but sometimes, maybe one isn't available, or maybe the specialized tool you are using is insisting on a regular expression and nothing else.
Because you are using quantified subpattern and as descried in Perl Doc,
By default, a quantified subpattern is "greedy", that is, it will
match as many times as possible (given a particular starting location)
while still allowing the rest of the pattern to match. If you want it
to match the minimum number of times possible, follow the quantifier
with a "?" . Note that the meanings don't change, just the
"greediness":
*? //Match 0 or more times, not greedily (minimum matches)
+? //Match 1 or more times, not greedily
Thus, to allow your quantified pattern to make minimum match, follow it by ? :
/location="(.*?)"/
import regex
text = 'ask her to call Mary back when she comes back'
p = r'(?i)(?s)call(.*?)back'
for match in regex.finditer(p, str(text)):
print (match.group(1))
Output:
Mary

regex to find a pattern in a string and replace it with another pattern [duplicate]

I need to match two cases by one reg expression and do replacement
'long.file.name.jpg' -> 'long.file.name_suff.jpg'
'long.file.name_a.jpg' -> 'long.file.name_suff.jpg'
I'm trying to do the following
re.sub('(\_a)?\.[^\.]*$' , '_suff.',"long.file.name.jpg")
But this is cut the extension '.jpg' and I'm getting
long.file.name_suff. instead of long.file.name_suff.jpg
I understand that this is because of [^.]*$ part, but I can't exclude it, because
I have to find last occurance of '_a' to replace or last '.'
Is there a way to replace only part of the match?
Put a capture group around the part that you want to preserve, and then include a reference to that capture group within your replacement text.
re.sub(r'(\_a)?\.([^\.]*)$' , r'_suff.\2',"long.file.name.jpg")
re.sub(r'(?:_a)?\.([^.]*)$', r'_suff.\1', "long.file.name.jpg")
?: starts a non matching group (SO answer), so (?:_a) is matching the _a but not enumerating it, the following question mark makes it optional.
So in English, this says, match the ending .<anything> that follows (or doesn't) the pattern _a
Another way to do this would be to use a lookbehind (see here). Mentioning this because they're super useful, but I didn't know of them for 15 years of doing REs
Just put the expression for the extension into a group, capture it and reference the match in the replacement:
re.sub(r'(?:_a)?(\.[^\.]*)$' , r'_suff\1',"long.file.name.jpg")
Additionally, using the non-capturing group (?:…) will prevent re to store to much unneeded information.
You can do it by excluding the parts from replacing. I mean, you can say to the regex module; "match with this pattern, but replace a piece of it".
re.sub(r'(?<=long.file.name)(\_a)?(?=\.([^\.]*)$)' , r'_suff',"long.file.name.jpg")
>>> 'long.file.name_suff.jpg'
long.file.name and .jpg parts are being used on matching, but they are excluding from replacing.
I wanted to use capture groups to replace a specific part of a string to help me parse it later. Consider the example below:
s= '<td> <address> 110 SOLANA ROAD, SUITE 102<br>PONTE VEDRA BEACH, FL32082 </address> </td>'
re.sub(r'(<address>\s.*?)(<br>)(.*?\<\/address>)', r'\1 -- \3', s)
##'<td> <address> 110 SOLANA ROAD, SUITE 102 -- PONTE VEDRA BEACH, FL32082 </address> </td>'
print(re.sub('name(_a)?','name_suff','long.file.name_a.jpg'))
# long.file.name_suff.jpg
print(re.sub('name(_a)?','name_suff','long.file.name.jpg'))
# long.file.name_suff.jpg

Need a python regular expression that can verify names with special characters(Hyphens, apostrophes, etc...)

I am trying to create a python regular expression that can match any name. I am scraping a web page and looking for the <h1> tag and grabbing the name in between it. The names can include James Dean, James-Dean, Brian O'Quin, Jame Joe-Harden, etc...
This was the first regular expression I have been working with but it is not catching all the names
<h1>[A-Z]{1}[a-z]+\s[A-Z]{1}[']?[A-Z]?[-]?[A-Z]?[a-z]+
Maybe this:
<h1>(([-'\w]+\s?)+)<h1>
Explaining:
the - matches itself, \w matches letters and numbers, and the plus is to capture one or more of these occurrences. Also, is optional a space character after this, to support composed names.
Finally, the last + plus ensures that you can repeat the structure I've just described.
Hope this help.

Python regex replace string preserver wild char [duplicate]

I need to match two cases by one reg expression and do replacement
'long.file.name.jpg' -> 'long.file.name_suff.jpg'
'long.file.name_a.jpg' -> 'long.file.name_suff.jpg'
I'm trying to do the following
re.sub('(\_a)?\.[^\.]*$' , '_suff.',"long.file.name.jpg")
But this is cut the extension '.jpg' and I'm getting
long.file.name_suff. instead of long.file.name_suff.jpg
I understand that this is because of [^.]*$ part, but I can't exclude it, because
I have to find last occurance of '_a' to replace or last '.'
Is there a way to replace only part of the match?
Put a capture group around the part that you want to preserve, and then include a reference to that capture group within your replacement text.
re.sub(r'(\_a)?\.([^\.]*)$' , r'_suff.\2',"long.file.name.jpg")
re.sub(r'(?:_a)?\.([^.]*)$', r'_suff.\1', "long.file.name.jpg")
?: starts a non matching group (SO answer), so (?:_a) is matching the _a but not enumerating it, the following question mark makes it optional.
So in English, this says, match the ending .<anything> that follows (or doesn't) the pattern _a
Another way to do this would be to use a lookbehind (see here). Mentioning this because they're super useful, but I didn't know of them for 15 years of doing REs
Just put the expression for the extension into a group, capture it and reference the match in the replacement:
re.sub(r'(?:_a)?(\.[^\.]*)$' , r'_suff\1',"long.file.name.jpg")
Additionally, using the non-capturing group (?:…) will prevent re to store to much unneeded information.
You can do it by excluding the parts from replacing. I mean, you can say to the regex module; "match with this pattern, but replace a piece of it".
re.sub(r'(?<=long.file.name)(\_a)?(?=\.([^\.]*)$)' , r'_suff',"long.file.name.jpg")
>>> 'long.file.name_suff.jpg'
long.file.name and .jpg parts are being used on matching, but they are excluding from replacing.
I wanted to use capture groups to replace a specific part of a string to help me parse it later. Consider the example below:
s= '<td> <address> 110 SOLANA ROAD, SUITE 102<br>PONTE VEDRA BEACH, FL32082 </address> </td>'
re.sub(r'(<address>\s.*?)(<br>)(.*?\<\/address>)', r'\1 -- \3', s)
##'<td> <address> 110 SOLANA ROAD, SUITE 102 -- PONTE VEDRA BEACH, FL32082 </address> </td>'
print(re.sub('name(_a)?','name_suff','long.file.name_a.jpg'))
# long.file.name_suff.jpg
print(re.sub('name(_a)?','name_suff','long.file.name.jpg'))
# long.file.name_suff.jpg

Regular expression pattern questions?

I am having a hard time understanding regular expression pattern. Could someone help me regular expression pattern to match all words ending in s. And start with a and end with a (like ana).
How do I write ending?
Word boundaries are given by \b so the following regex matches words ending with ing or s: "\b(\w+?(?:ing|s))\b" where as \b is a word boundary, \w+ is one or more "word character" and (?:ing|s) is an uncaptured group of either ing or s.
As you asked "how to develop a regex":
First: Don't use regex for complex tasks. They are hard to read, write and maintain. For example there is a regex that validates email addresses - but its computer generated and nothing you should use in practice.
Start simple and add edge cases. At the beginning plan what characters you need to use: You said you need words ending with s or ing. So you probably need something to represent a word, endings of words and the literal characters s and ing. What is a word? This might change from case to case, but at least every alphabetical character. Looking up in the python documentation on regexes you can find \w which is [a-zA-Z0-9_], which fits my impression of a word character. There you can also find \b which is a word boundary.
So the "first pseudo code try" is something like \b\w...\w\b which matches a word. We still need to "formalize" ... which we want to have the meaning of "one ore more characters", which directly translates to \b\w+\b. We can now match a word! We still need the s or ing. | translates to or, so how is the following: \b\w+ing|s\b? If you test this, you'll see that it will match confusing things like ingest which should not match our regex. What is happening? As you probably already saw the | can't know "which part it should or", so we need to introduce parenthesis: \b\w+(ing|s)\b. Congratulations, you have now arrived at a working regex!
Why (and how) does this differ from the example I gave first? First I wrote \w+? instead of \w+, the ? turns the + into a non-greedy version. If you know what the difference between greedy and non greedy is, skip this paragraph. Consider the following: AaAAbA and we want to match the things enclosed with big letter A. A naive try: A\w+A, so one or more word characters enclosed with A. This matches AaA, but also AaAAbA, A is still something that can be matched by \w. Without further config the *+? quantifier all try to match as much as possible. Sometimes, like in the A example, you don't want that, you can then use a ? after the quantifier to signal you want a non-greedy version, a version that matches as little as possible.
But in our case this isn't needed, the words are well seperated by whitespaces, which are not part of \w. So in fact you can just let + be greedy and everything will be alright. If you use . (any character) you often need to be careful not to match to much.
The other difference is using (?:s|ing) instead of (s|ing). What does the ?: do here? It changes a capturing group to a non capturing group. Generally you don't want to get "everything" from the regex. Consider the following regex: I want to go to \w+. You are not interested in the whole sentence, but only in the \w+, so you can capture it in a group: I want to go to (\w+). This means that you are interested in this specific piece of information and want to retrieve it later. Sometimes (like when using |) you need to group expressions together, but are not interested in their content, you can then declare it as non capturing. Otherwise you will get the group (s or ing) but not the actual word!
So to summarize:
* start small
* add one case after another
* always test with examples
In fact I just tried re.findall(\b\w+(?:ing|s)\b, "fishing words") and it didn't work. \w+(?:ing|s) works. I've no idea why, maybe someone else can explain that. Regex are an arcane thing, only use them for easy and easy to test tasks.
Generally speaking I'd use \b to match "word boundaries" with \w which matches word components (short cut for [A-Za-z0-9_]). Then you can do an or grouping to match "s" or "ing". Result is:
/\b\w+(s|ing)\b/

Categories

Resources