re.Match

One successful match. Its repr shows the span and the text; methods (group, groups, groupdict, start, end, span, expand) read the parts, and a handful of attributes describe how the search was run. It is always truthy — failure is None, not an empty Match.

re classPython 3 (all)Live demo
Common call
m = re.search(r'(\w+)@(\w+)', text)
Returns
<re.Match object; span=(5, 13), match='ada@home'>
Replaces
tracking indexes by hand after str.find
Watch out
lastindex is the last group that CLOSED, not the highest-numbered group that matched
class re.Match
→ re.Match

Demo

Live evaluation
Which group closed last, its name, and every span at once.
Try:
Inputs
patternstra regular expression with groups
textstrtext
Code
import re
m = re.search('(?P<num>\\d+)|(?P<word>[a-z]+)', '  hello 42')
(m.lastindex, m.lastgroup, m.regs)
Result
(2, 'word', ((2, 7), (-1, -1), (2, 7)))

In the alternation case only the word branch matched, so lastindex is 2 and lastgroup is word; group 1 shows (-1, -1) in regs. For ((a)(b)) the outer group 1 closes last, so lastindex is 1 even though groups 2 and 3 matched. A failed search returns None, and reading .lastindex on it raises AttributeError. endpos is clamped to len(string).

Attributes

AttributeTypeMeaning
posintThe pos passed to search()/match() — where scanning started (0 by default)
endposintThe endpos passed — the scan limit (len(string) by default)
lastindexint | NoneNumber of the last group that was closed during the match; None if no group matched
lastgroupstr | NoneName of that last closed group; None if it has no name or no group matched
rere.PatternThe compiled pattern that produced this match
stringstrThe string that was searched (the whole string, not just the match)
regstupleUndocumented: ((start, end), …) for group 0 and every group, (-1, -1) when unmatched — the same as span(i) for each i

Common patterns

Always test for None first
search/match/fullmatch return None on failure.
import re
def first_number(text):
    m = re.search(r'\d+', text)
    if m is None:
        return None
    return int(m.group())
Which alternative matched?
Name each branch and read lastgroup — a compact tokenizer.
import re
TOKEN = re.compile(r'(?P<NUM>\d+)|(?P<NAME>[A-Za-z_]\w*)|(?P<OP>[-+*/=])|(?P<WS>\s+)')
tokens = [(m.lastgroup, m.group()) for m in TOKEN.finditer(src) if m.lastgroup != 'WS']
Type hints
re.Match is generic since 3.9.
import re
def first_word(text: str) -> re.Match[str] | None:
    return re.search(r"\w+", text)

Examples

1. The repr
import re re.search(r'\d+', 'order 66')
Returns
<re.Match object; span=(6, 8), match='66'>
2. Always truthy
import re bool(re.search('', 'abc'))
Returns
True
3. lastindex and lastgroup
import re m = re.search(r'(?P<user>\w+)@(?P<host>[\w.]+)', 'mail ada@example.com now') (m.lastindex, m.lastgroup)
Returns
(2, 'host')
4. Outer group closes last
import re re.match(r'(a(b))', 'ab').lastindex
Returns
1
5. pos and endpos
import re m = re.compile(r'\d').search('ab12', 2) (m.pos, m.endpos)
Returns
(2, 4)
6. re and string
import re m = re.search(r'b', 'abc') (m.re, m.string)
Returns
(re.compile('b'), 'abc')
7. regs: every span
import re re.match(r'(a)(b)?', 'a').regs
Returns
((0, 1), (0, 1), (-1, -1))

Pitfalls

1. Using lastindex as "number of groups matched"
It is the index of the group that closed last. For the count of groups use m.re.groups; for which ones matched, check groups() for None.
lastindex
import re
re.match(r'((a)(b))', 'ab').lastindex
1
groups()
import re
m = re.match(r'((a)(b))', 'ab')
sum(g is not None for g in m.groups())
3
2. Keeping Match objects of huge strings
A Match holds a reference to the entire searched string (m.string). Keep m.group() instead if you store results.
store m
import re
text = 'x' * 1000 + '42'
m = re.search(r'\d+', text)
len(m.string)
1002
store the text
import re
text = 'x' * 1000 + '42'
found = re.search(r'\d+', text).group()
len(found)
2

When to use

Use it
  • Getting positions, groups and the pattern behind a result
  • Dispatching on which named alternative matched (lastgroup)
Reach for something else
  • Testing for "empty match" with bool(m) — a Match is always True; compare m.group() == ''
  • regs in new code — it is undocumented; use span(i)

Notes

CPython impl
MatchObject in Modules/_sre/_sre.c. The repr is <re.Match object; span=(start, end), match=repr(text)> with the text repr cut to 50 characters
Indexing
m[g] is the same as m.group(g) (Python 3.6+)
Generic
re.Match[str] / re.Match[bytes] in annotations since Python 3.9
Copy
copy.copy() and copy.deepcopy() return the same object (3.7+)

FAQ

The object search, match and fullmatch return on success (and finditer yields). It holds the matched text, its position and every group — its repr looks like <re.Match object; span=(6, 8), match='66'>.