re.search

The one you usually want: tries every position from left to right and stops at the first match. Also available as Pattern.search(string, pos, endpos) on a compiled pattern.

re functionPython 3 (all)Live demo
Common call
re.search(r'\d+', 'order 66')
Returns
<re.Match object; span=(6, 8), match='66'> or None
Replaces
str.find / the in operator when the target is a pattern, not fixed text
Watch out
None when nothing matches — check before calling .group()
re.search(patternpattern — The regular expression — write it as a raw string, r'...'.type: str | re.Pattern · required, stringstring — The text to scan.type: str · required, flagsflags — re.IGNORECASE, re.MULTILINE, … combined with |. Not allowed when pattern is already compiled.type: re.RegexFlag | int · default: 0=0)
→ re.Match | None

Demo

Live evaluation
The Match object shows where the first match is (span) and what it matched.
Try:
Inputs
patternstra regular expression
textstrtext to scan
Code
import re
re.search('\\d+', 'order 66, then 3')
Result
<re.Match object; span=(6, 8), match='66'>

span=(start, end) is a half-open range: text[start:end] is the match. An empty match is still a match — x* finds zero x at position 0, so search returns a Match (truthy) with span=(0, 0). In the pos tab, ^\d+ fails at pos 3 because ^ only matches at the true beginning of the string; pos past the end is clamped to the end.

Parameters

NameTypeRequiredDescription
patternstr | re.PatternyesThe regular expression — write it as a raw string, r'...'.
stringstryesThe text to scan.
flagsre.RegexFlag | intno (0)re.IGNORECASE, re.MULTILINE, … combined with |. Not allowed when pattern is already compiled.

Return value

re.Match | None — The first match (leftmost position), or None when the pattern matches nowhere.

Common patterns

Test and use in one step
The walrus operator keeps the Match object for the body.
import re
if m := re.search(r'(\d+) items?', line):
    count = int(m.group(1))
Does the text contain the pattern?
A Match is truthy, None is falsy.
import re
has_digit = re.search(r'\d', password) is not None
Compiled pattern in a loop
Pattern.search takes optional pos and endpos to limit the scan.
import re
ERR = re.compile(r'\bERROR\b')
errors = [ln for ln in log_lines if ERR.search(ln)]

Examples

1. The first match wins
import re re.search(r'\d+', 'order 66, then 3')
Returns
<re.Match object; span=(6, 8), match='66'>
2. Get the matched text
import re re.search(r'\d+', 'order 66').group()
Returns
'66'
3. No match is None
import re re.search(r'\d+', 'no digits') is None
Returns
True
4. Groups inside the match
import re m = re.search(r'(\w+)@(\w+)\.com', 'mail ada@example.com') m.groups()
Returns
('ada', 'example')
5. Case-insensitive
import re re.search(r'error', 'Disk ERROR', re.IGNORECASE)
Returns
<re.Match object; span=(5, 10), match='ERROR'>
6. Pattern.search with pos
import re re.compile(r'\d').search('ab12', 2)
Returns
<re.Match object; span=(2, 3), match='1'>
7. ^ ignores pos
import re print(re.compile(r'^\d').search('ab12', 2))
Returns
None

Pitfalls

1. An empty match is not "no match"
A pattern that can match nothing (x*, \d?) always succeeds, at position 0. Require at least one character with + instead of *.
r'\d*'
import re
re.search(r'\d*', 'abc 42')
<re.Match object; span=(0, 0), match=''>
r'\d+'
import re
re.search(r'\d+', 'abc 42')
<re.Match object; span=(4, 6), match='42'>
2. Passing flags to a compiled pattern
Flags belong to compile(). re.search with a Pattern object and flags raises ValueError.
flags twice
import re
pat = re.compile(r'abc')
re.search(pat, 'ABC', re.I)
ValueError: cannot process flags argument with a compiled pattern
flags at compile
import re
pat = re.compile(r'abc', re.I)
pat.search('ABC')
<re.Match object; span=(0, 3), match='ABC'>

When to use

Use it
  • Finding whether and where a pattern occurs anywhere in a string
  • Extracting the first occurrence with its groups
Reach for something else
  • Must match at the start → re.match; the whole string → re.fullmatch
  • Need every occurrence → re.findall or re.finditer
  • Fixed text → the in operator or str.find

Notes

CPython impl
Pattern.search runs the matcher at each position from pos to endpos (SRE search in Modules/_sre/sre_lib.h), with shortcuts when the pattern starts with literal text
pos/endpos
Pattern.search(string, pos=0, endpos=len): endpos behaves like slicing the string, but pos does not — ^ and lookbehind still see the characters before pos
Truthiness
A Match object is always true, even for an empty match; test with is None / is not None

FAQ

A re.Match object for the first match, or None. The Match gives the text (m.group()), its position (m.start(), m.end(), m.span()) and the groups. Its repr looks like <re.Match object; span=(6, 8), match='66'>.