Python extract pattern matches
Question:
I am trying to use a regular expression to extract words inside of a pattern.
I have some string that looks like this
someline abc
someother line
name my_user_name is valid
some more lines
I want to extract the word my_user_name
. I do something like
import re
s = #that big string
p = re.compile("name .* is valid", re.flags)
p.match(s) # this gives me <_sre.SRE_Match object at 0x026B6838>
How do I extract my_user_name
now?
Answers:
You can use matching groups:
p = re.compile('name (.*) is valid')
e.g.
>>> import re
>>> p = re.compile('name (.*) is valid')
>>> s = """
... someline abc
... someother line
... name my_user_name is valid
... some more lines"""
>>> p.findall(s)
['my_user_name']
Here I use re.findall
rather than re.search
to get all instances of my_user_name
. Using re.search
, you’d need to get the data from the group on the match object:
>>> p.search(s) #gives a match object or None if no match is found
<_sre.SRE_Match object at 0xf5c60>
>>> p.search(s).group() #entire string that matched
'name my_user_name is valid'
>>> p.search(s).group(1) #first group that match in the string that matched
'my_user_name'
As mentioned in the comments, you might want to make your regex non-greedy:
p = re.compile('name (.*?) is valid')
to only pick up the stuff between 'name '
and the next ' is valid'
(rather than allowing your regex to pick up other ' is valid'
in your group.
You need to capture from regex. search
for the pattern, if found, retrieve the string using group(index)
. Assuming valid checks are performed:
>>> p = re.compile("name (.*) is valid")
>>> result = p.search(s)
>>> result
<_sre.SRE_Match object at 0x10555e738>
>>> result.group(1) # group(1) will return the 1st capture (stuff within the brackets).
# group(0) will returned the entire matched text.
'my_user_name'
You want a capture group.
p = re.compile("name (.*) is valid", re.flags) # parentheses for capture groups
print p.match(s).groups() # This gives you a tuple of your matches.
You could use something like this:
import re
s = #that big string
# the parenthesis create a group with what was matched
# and 'w' matches only alphanumeric charactes
p = re.compile("name +(w+) +is valid", re.flags)
# use search(), so the match doesn't have to happen
# at the beginning of "big string"
m = p.search(s)
# search() returns a Match object with information about what was matched
if m:
name = m.group(1)
else:
raise Exception('name not found')
Maybe that’s a bit shorter and easier to understand:
>>> import re
>>> text = '... someline abc... someother line... name my_user_name is valid.. some more lines'
>>> re.search('name (.*) is valid', text).group(1)
'my_user_name'
You can use groups (indicated with '('
and ')'
) to capture parts of the string. The match object’s group()
method then gives you the group’s contents:
>>> import re
>>> s = 'name my_user_name is valid'
>>> match = re.search('name (.*) is valid', s)
>>> match.group(0) # the entire match
'name my_user_name is valid'
>>> match.group(1) # the first parenthesized subgroup
'my_user_name'
In Python 3.6+ you can also index into a match object instead of using group()
:
>>> match[0] # the entire match
'name my_user_name is valid'
>>> match[1] # the first parenthesized subgroup
'my_user_name'
Here’s a way to do it without using groups (Python 3.6 or above):
>>> re.search('2ddd[01]d[0-3]d', 'report_20191207.xml')[0]
'20191207'
You can also use a capture group (?P<user>pattern)
and access the group like a dictionary match['user']
.
string = '''someline abcn
someother linen
name my_user_name is validn
some more linesn'''
pattern = r'name (?P<user>.*) is valid'
matches = re.search(pattern, str(string), re.DOTALL)
print(matches['user'])
# my_user_name
It seems like you’re actually trying to extract a name vice simply find a match. If this is the case, having span indexes for your match is helpful and I’d recommend using re.finditer
. As a shortcut, you know the name
part of your regex is length 5 and the is valid
is length 9, so you can slice the matching text to extract the name.
Note – In your example, it looks like s
is string with line breaks, so that’s what’s assumed below.
## covert s to list of strings separated by line:
s2 = s.splitlines()
## find matches by line:
for i, j in enumerate(s2):
matches = re.finditer("name (.*) is valid", j)
## ignore lines without a match
if matches:
## loop through match group elements
for k in matches:
## get text
match_txt = k.group(0)
## get line span
match_span = k.span(0)
## extract username
my_user_name = match_txt[5:-9]
## compare with original text
print(f'Extracted Username: {my_user_name} - found on line {i}')
print('Match Text:', match_txt)
I found this answer via google because I wanted to unpack a re.search()
result with multiple groups directly into multiple variables. While this might be obvious for some, it was not for me because I always used group()
in the past, so maybe it helps someone in the future who also did not know about group*s*()
.
s = "2020:12:30"
year, month, day = re.search(r"(d+):(d+):(d+)", s).groups()
I am trying to use a regular expression to extract words inside of a pattern.
I have some string that looks like this
someline abc
someother line
name my_user_name is valid
some more lines
I want to extract the word my_user_name
. I do something like
import re
s = #that big string
p = re.compile("name .* is valid", re.flags)
p.match(s) # this gives me <_sre.SRE_Match object at 0x026B6838>
How do I extract my_user_name
now?
You can use matching groups:
p = re.compile('name (.*) is valid')
e.g.
>>> import re
>>> p = re.compile('name (.*) is valid')
>>> s = """
... someline abc
... someother line
... name my_user_name is valid
... some more lines"""
>>> p.findall(s)
['my_user_name']
Here I use re.findall
rather than re.search
to get all instances of my_user_name
. Using re.search
, you’d need to get the data from the group on the match object:
>>> p.search(s) #gives a match object or None if no match is found
<_sre.SRE_Match object at 0xf5c60>
>>> p.search(s).group() #entire string that matched
'name my_user_name is valid'
>>> p.search(s).group(1) #first group that match in the string that matched
'my_user_name'
As mentioned in the comments, you might want to make your regex non-greedy:
p = re.compile('name (.*?) is valid')
to only pick up the stuff between 'name '
and the next ' is valid'
(rather than allowing your regex to pick up other ' is valid'
in your group.
You need to capture from regex. search
for the pattern, if found, retrieve the string using group(index)
. Assuming valid checks are performed:
>>> p = re.compile("name (.*) is valid")
>>> result = p.search(s)
>>> result
<_sre.SRE_Match object at 0x10555e738>
>>> result.group(1) # group(1) will return the 1st capture (stuff within the brackets).
# group(0) will returned the entire matched text.
'my_user_name'
You want a capture group.
p = re.compile("name (.*) is valid", re.flags) # parentheses for capture groups
print p.match(s).groups() # This gives you a tuple of your matches.
You could use something like this:
import re
s = #that big string
# the parenthesis create a group with what was matched
# and 'w' matches only alphanumeric charactes
p = re.compile("name +(w+) +is valid", re.flags)
# use search(), so the match doesn't have to happen
# at the beginning of "big string"
m = p.search(s)
# search() returns a Match object with information about what was matched
if m:
name = m.group(1)
else:
raise Exception('name not found')
Maybe that’s a bit shorter and easier to understand:
>>> import re
>>> text = '... someline abc... someother line... name my_user_name is valid.. some more lines'
>>> re.search('name (.*) is valid', text).group(1)
'my_user_name'
You can use groups (indicated with '('
and ')'
) to capture parts of the string. The match object’s group()
method then gives you the group’s contents:
>>> import re
>>> s = 'name my_user_name is valid'
>>> match = re.search('name (.*) is valid', s)
>>> match.group(0) # the entire match
'name my_user_name is valid'
>>> match.group(1) # the first parenthesized subgroup
'my_user_name'
In Python 3.6+ you can also index into a match object instead of using group()
:
>>> match[0] # the entire match
'name my_user_name is valid'
>>> match[1] # the first parenthesized subgroup
'my_user_name'
Here’s a way to do it without using groups (Python 3.6 or above):
>>> re.search('2ddd[01]d[0-3]d', 'report_20191207.xml')[0]
'20191207'
You can also use a capture group (?P<user>pattern)
and access the group like a dictionary match['user']
.
string = '''someline abcn
someother linen
name my_user_name is validn
some more linesn'''
pattern = r'name (?P<user>.*) is valid'
matches = re.search(pattern, str(string), re.DOTALL)
print(matches['user'])
# my_user_name
It seems like you’re actually trying to extract a name vice simply find a match. If this is the case, having span indexes for your match is helpful and I’d recommend using re.finditer
. As a shortcut, you know the name
part of your regex is length 5 and the is valid
is length 9, so you can slice the matching text to extract the name.
Note – In your example, it looks like s
is string with line breaks, so that’s what’s assumed below.
## covert s to list of strings separated by line: s2 = s.splitlines() ## find matches by line: for i, j in enumerate(s2): matches = re.finditer("name (.*) is valid", j) ## ignore lines without a match if matches: ## loop through match group elements for k in matches: ## get text match_txt = k.group(0) ## get line span match_span = k.span(0) ## extract username my_user_name = match_txt[5:-9] ## compare with original text print(f'Extracted Username: {my_user_name} - found on line {i}') print('Match Text:', match_txt)
I found this answer via google because I wanted to unpack a re.search()
result with multiple groups directly into multiple variables. While this might be obvious for some, it was not for me because I always used group()
in the past, so maybe it helps someone in the future who also did not know about group*s*()
.
s = "2020:12:30"
year, month, day = re.search(r"(d+):(d+):(d+)", s).groups()