Python first match

PYTHON Published Updated 3 mins read By Leon Wei
Python first match cover image

Quick summary

Summarize this blog with AI

“First match” can mean three different results: a substring offset, a regular-expression match object, or an item from an iterable. Choose the result contract first. All examples run on Python 3.12.14 with the standard library.

NeedToolNo match
Substring positiontext.find(needle)-1
Pattern and captured textre.search(pattern, text)None
First qualifying itemnext(generator, default)The chosen default

Treat position zero as a successful match

text = "Python and SQL"
for needle in ["Python", "SQL", "R", ""]:
    position = text.find(needle)
    print(repr(needle), position, position != -1)
print("Python" in text)

Expected output:

'Python' 0 True
'SQL' 11 True
'R' -1 False
'' 0 True
True

if text.find(...) is wrong for existence: zero is falsy, while -1 is truthy. Use in when you only need membership, or compare the offset with -1. Empty text is a substring at position zero under this contract. Search is case-sensitive; any case normalization must be deliberate. Python string offsets count Unicode code points, not encoded bytes or necessarily whole displayed grapheme clusters.

Inspect the regex Match instead of treating it as an index

import re
text = "id=17; id=42"
match = re.search(r"id=(\d+)", text)
if match is not None:
    print(match.group(0), match.group(1), match.span())
print(re.search(r"name=(\w+)", text) is None)
print(re.match(r"id=", "prefix id=17") is None)
print(re.fullmatch(r"\d+", "17x") is None)

Expected output:

id=17 17 (0, 5)
True
True
True

search looks for the first matching position, match starts at the beginning, and fullmatch requires the entire input. The group text and span are separate properties. Regex alternation and greediness still determine what matches at that position; “first” does not mean shortest. For a literal user-provided substring, prefer string methods or escape it with re.escape rather than interpreting it as a pattern. Bound untrusted input and avoid patterns with pathological backtracking.

Use a sentinel when None can itself be a valid item

MISSING = object()
values = [None, 0, 7, 9]
first = next((value for value in values if value is None), MISSING)
print(first is None, first is MISSING)
print(next((n for n in [] if n > 5), MISSING) is MISSING)
print(next((pair for pair in enumerate([2, 8, 8]) if pair[1] > 5), None))
stream = iter([2, 8, 9])
print(next((n for n in stream if n > 5), None))
print(list(stream))

Expected output:

True False
True
(1, 8)
8
[9]

The generator stops at the first qualifying item and leaves the source iterator after that item. A reusable list remains intact; a generator or file iterator is consumed. If absence is exceptional, omit the default and handle StopIteration at the correct boundary. If you need both position and value, return an enumerate pair as shown. An empty input is a normal no-match case, not an indexing error.

Define ordering and missing-data rules

A first matching record depends on input order. Sort under a documented key first if “first” means earliest timestamp, and include a tie-breaker when one winner is required. Do not convert an unordered set to a list and call its first element meaningful. For a missing dictionary field, decide whether the record is invalid or should be skipped; an accidental default can hide bad data. Test a match at position zero, no match, repeated matches, empty input, and a valid item equal to your proposed default.

References and next steps

String find, Regex search, next.

Interview Prep

Begin Your SQL, Python, and R Journey

Master 230 interview-style coding questions and build the data skills needed for analyst, scientist, and engineering roles.

Related Articles

All Articles
Python string concatenation cover image
python Oct 17, 2026

Python string concatenation

Explore the essential of string concatenation in Python Learn to merge strings with practical code examples, a key skill for crafting dynamic te…