Python Regex Match Length: Groups, Spans and Empty Matches
Published · Updated
For a successful Python regex match, use len(m.group(0)) or m.end(0) - m.start(0) to measure the whole matched text. Check that m is not None first. Measuring the pattern string answers a different question.
Read the result, not the pattern
The Python Regular Expression HOWTO shows how a match object exposes its text and positions. For re.search(r"ab+", "abbb"), the pattern string has three characters, but the matched text has four. The span (0, 4) starts at index zero and ends just after the last matched code point.
These examples use Python str input and the standard-library re module. The final column measures group zero, the complete match. An unsuccessful search has no matched-text length.
| Pattern | Input | Whole-match span | Length |
|---|---|---|---|
| ab+ | abbb | (0, 4) | 4 |
| (ab)+ | abab | (0, 4) | 4 |
| (?=ab) | ab | (0, 0) | 0 |
| z+ | ab | None | not applicable |
| .+ | é😀 | (0, 2) | 2 |
Choose the capture group deliberately
Match group zero is the entire match. A numbered or named capture can be shorter. With re.search(r"(ab)+", "abab"), group zero is abab, length four; group one is the last captured ab, length two.
An optional group can be absent even when the whole expression matches. For re.search(r"(a)?b", "b"), group one is None and its span is (-1, -1). Do not subtract those sentinel positions and report a successful zero-length capture. Check the selected group’s participation before measuring it.
Keep empty matches separate from no match
re.search(r"(?=ab)", "ab") succeeds at (0, 0): the lookahead consumes no text. By contrast, re.search(r"z+", "ab") returns None. A participating empty group also differs from an absent group: (a*)b on b captures an empty string in group one.
Measure a named capture and its bytes
In Python’s text type, a string is a sequence of Unicode code points. The capture é😀 contains two code points and six UTF-8 bytes. This in-memory example keeps the whole span, capture span and encoded size separate:
import re
text = "ID: é😀"
m = re.search(r"ID: (?P<value>.+)", text)
if m is None:
raise ValueError("No match")
value = m.group("value")
print(m.span(0), m.end(0) - m.start(0))
print(m.span("value"), len(value), len(value.encode("utf-8")))
The output is (0, 6) 6, then (4, 6) 2 6. The prefix belongs to the whole match but is outside the named capture. For bytes input with a bytes pattern, positions instead refer to bytes. A code point count is also not a grapheme count: e followed by U+0301 has length two in a Python string.
Count occurrences as a separate operation
re.finditer yields match objects for non-overlapping matches, including empty matches. On ab ab, pattern ab produces two objects, each with a matched-text length of two. The number of objects and each object’s length answer different questions. findall returns strings or tuples depending on capture groups, so an item’s length may describe a capture or tuple rather than the whole match.
The Count in Python guide covers total lengths and literal occurrence counts; the String Length guide explains counting units. Use the rule required by the receiving field when applying a length limit. Measuring a regex result does not establish that limit or make a pattern safe or fast.