re — regular expressions#

Part of a series demonstrating the 5 most-imported modules across the top PyPI packages (from imports_ranked.csv). Rank 5 of 5 — imported by 60.6% of crawled packages.

Pattern matching and text extraction. Core functions: search, match, fullmatch, findall, finditer, sub, split, and compile.

search vs match vs fullmatch#

match anchors at the start, fullmatch must consume the whole string, search scans anywhere.

import re

s = 'order 12345 shipped'
print('search   :', re.search(r'\d+', s))
print('match    :', re.match(r'\d+', s))          # None: starts with letters
print('match    :', re.match(r'\w+', s))          # matches 'order'
print('fullmatch:', re.fullmatch(r'[\w ]+', s))
search   : <re.Match object; span=(6, 11), match='12345'>
match    : None
match    : <re.Match object; span=(0, 5), match='order'>
fullmatch: <re.Match object; span=(0, 19), match='order 12345 shipped'>

Capturing groups — named and numbered#

import re

m = re.search(r'(?P<year>\d{4})-(?P<month>\d{2})', '2026-08 report')
print('group(0):', m.group(0))
print('year    :', m.group('year'))
print('month   :', m.group(2))
print('groupdict:', m.groupdict())
group(0): 2026-08
year    : 2026
month   : 08
groupdict: {'year': '2026', 'month': '08'}

findall and finditer — all matches#

import re

text = 'contact ada@x.io or linus@y.org today'
print('findall :', re.findall(r'[\w.]+@[\w.]+', text))

for m in re.finditer(r'[\w.]+@[\w.]+', text):
    print(f'  {m.group()} at [{m.start()}:{m.end()}]')
findall : ['ada@x.io', 'linus@y.org']
  ada@x.io at [8:16]
  linus@y.org at [20:31]

sub and split — replace and tokenise#

import re

print(re.sub(r'\s+', '_', 'a   b \t c'))          # collapse whitespace
print(re.sub(r'(\w+)@\w+', r'\1@***', 'bob@corp'))  # backreference
print(re.split(r'[,;\s]+', 'a, b;c   d'))          # split on any delimiter
a_b_c
bob@***
['a', 'b', 'c', 'd']

compile and flags#

Compile once, reuse many times. Flags like IGNORECASE and MULTILINE tune matching.

import re

pat = re.compile(r'^error', re.IGNORECASE | re.MULTILINE)
log = 'Error: disk full\nok\nERROR: timeout'
print('matches:', pat.findall(log))
print('count  :', len(pat.findall(log)))
matches: ['Error', 'ERROR']
count  : 2

Escaping literal text: re.escape#

Safely match strings that contain regex metacharacters.

import re

user_input = 'a.b*c'
print('escaped:', re.escape(user_input))
print('found  :', bool(re.search(re.escape(user_input), 'xa.b*cy')))
escaped: a\.b\*c
found  : True