re.fullmatch

Both ends anchored: the pattern has to account for every character. Cleaner and stricter than wrapping a pattern in ^…$ — $ lets a trailing newline slip through. Also available as Pattern.fullmatch(string, pos, endpos).

re functionPython 3.4+Live demo
Common call
re.fullmatch(r'\d{5}', zip_code)
Returns
a Match for the entire string, or None
Replaces
re.match(r'^...$') and re.search(r'\A...\Z')
Watch out
Whole value only — to find the value inside longer text use re.search
re.fullmatch(patternpattern — The regular expression, as a raw string.type: str | re.Pattern · required, stringstring — The value to validate; all of it must match.type: str · required, flagsflags — Flags such as re.IGNORECASE. Not allowed with a compiled pattern.type: re.RegexFlag | int · default: 0=0)
→ re.Match | None

Demo

Live evaluation
None unless the pattern can cover the text from the first character to the last.
Try:
Inputs
patternstra regular expression
textstrvalue to validate
Code
import re
re.fullmatch('\\d{5}(-\\d{4})?', '90210-1234')
Result
<re.Match object; span=(0, 10), match='90210-1234'>

fullmatch backtracks until the match covers everything: .+? is lazy, yet fullmatch still returns all of 'abc', and with cat|category it moves on to the second alternative after 'cat' leaves text over. In the $ tab, \d+$ matches '42\n' in search and match because $ also matches just before a final newline; fullmatch rejects it.

Parameters

NameTypeRequiredDescription
patternstr | re.PatternyesThe regular expression, as a raw string.
stringstryesThe value to validate; all of it must match.
flagsre.RegexFlag | intno (0)Flags such as re.IGNORECASE. Not allowed with a compiled pattern.

Return value

re.Match | None — A match covering the entire string (from pos to endpos for Pattern.fullmatch), or None.

Common patterns

A validator function
Compile once; return a bool.
import re
USERNAME = re.compile(r'[a-z][a-z0-9_]{2,15}')
def valid_username(name):
    return USERNAME.fullmatch(name) is not None
Validate and parse at once
The groups of a full match are the parsed fields.
import re
if m := re.fullmatch(r'(\d{1,2}):(\d{2})', value):
    hours, minutes = int(m[1]), int(m[2])

Examples

1. The whole string matches
import re re.fullmatch(r'\d+', '12345')
Returns
<re.Match object; span=(0, 5), match='12345'>
2. Anything extra fails
import re print(re.fullmatch(r'\d+', '12345a'))
Returns
None
3. Stricter than $
import re (bool(re.match(r'\d+$', '123\n')), bool(re.fullmatch(r'\d+', '123\n')))
Returns
(True, False)
4. Backtracks to cover all
import re re.fullmatch(r'cat|category', 'category')
Returns
<re.Match object; span=(0, 8), match='category'>
5. Case-insensitive check
import re bool(re.fullmatch(r'yes|y', 'YES', re.IGNORECASE))
Returns
True
6. Pattern.fullmatch with endpos
import re re.compile(r'\d+').fullmatch('123abc', 0, 3)
Returns
<re.Match object; span=(0, 3), match='123'>

Pitfalls

1. Trusting ^...$ to validate
$ also matches before a trailing newline, so a value ending in \n passes. fullmatch (or \Z) does not.
r'^\d+$'
import re
bool(re.match(r'^\d+$', '42\n'))
True
fullmatch
import re
bool(re.fullmatch(r'\d+', '42\n'))
False
2. Anchors around an alternation
In ^cat|dog$ the anchors bind to one alternative each. fullmatch applies to the whole pattern, so no anchors or extra group are needed.
r'^cat|dog$'
import re
bool(re.match(r'^cat|dog$', 'catalog'))
True
fullmatch
import re
bool(re.fullmatch(r'cat|dog', 'catalog'))
False

When to use

Use it
  • Validating a complete value: IDs, codes, numbers, usernames
  • Parsing a string that has exactly one expected shape
Reach for something else
  • Looking for the pattern inside longer text → re.search
  • Checking just a prefix → re.match
  • Numbers you will convert anyway → try int(value) / float(value)

Notes

CPython impl
The matcher runs once at pos with a "match all" flag: a match only counts if it ends exactly at endpos, so the engine keeps backtracking for longer alternatives
Added
Python 3.4 (re.fullmatch and Pattern.fullmatch)
endpos
Pattern.fullmatch(string, pos, endpos) requires the match to cover exactly string[pos:endpos]

FAQ

re.fullmatch(pattern, s) — it returns a Match only if the entire string matches. For example re.fullmatch(r'\d{5}', '90210') matches but '90210x' does not.