findall, finditer and split

re · Essentials · 9 min

Pulling all numbers, emails or tokens out of text, and splitting on messy separators, are everyday jobs.

re.findall(pattern, text) returns all non-overlapping matches as a list:

  • with no groups, a list of matched strings;
  • with one group, a list of that group's text;
  • with several groups, a list of tuples.

re.finditer returns an iterator of Match objects instead. Use it when you need positions, named groups or both the whole match and its parts, and for big inputs since it doesn't build a list.

re.split(pattern, text) splits on every match of the pattern, where str.split handles only a fixed separator:

re.split(r"[,;\s]+", "a, b;c  d")   # ['a', 'b', 'c', 'd']

If the pattern contains a capturing group, the separators are included in the result, which is handy for tokenising but surprising otherwise; use (?:...) to avoid it. maxsplit= limits the number of splits.

Since 3.13, passing maxsplit (and count and flags in re.sub) positionally is deprecated: write re.split(p, s, maxsplit=1), not re.split(p, s, 1). Passing flags positionally to split was a classic bug, because re.split(p, s, re.I) set maxsplit=2.

Matches never overlap: after a match, scanning continues where it ended.

Example

import re

log = "ERROR 12ms user=ann; WARN 7ms user=bob; ERROR 30ms user=cy"
print(re.findall(r"\d+ms", log))              # ['12ms', '7ms', '30ms']
print(re.findall(r"(\d+)ms", log))            # ['12', '7', '30']
print(re.findall(r"(\w+) (\d+)ms", log)[:2])  # [('ERROR', '12'), ('WARN', '7')]

for m in re.finditer(r"user=(\w+)", log):
    print(m.group(1), m.start())
# ann 11
# bob 30
# cy 51

print(re.split(r"[,;\s]+", "a, b;c  d"))       # ['a', 'b', 'c', 'd']
print(re.split(r"([+-])", "3+4-1"))            # ['3', '+', '4', '-', '1']
print(re.split(r"\s+", "a b c", maxsplit=1))   # ['a', 'b c']

Remember

  • findall returns strings, group texts or tuples depending on the groups
  • finditer yields Match objects with positions, lazily
  • re.split includes captured separators; pass maxsplit by keyword

Watch out for

  • Calling re.split(p, s, re.IGNORECASE); the flag is taken as maxsplit (and is deprecated positionally since 3.13).

Check yourself

  1. What does re.findall(r'(\d)(\w)', 'a1b c2d') return?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.python.org/3/library/re.html#re.findall