Named groups and Match objects

re · Practical · 9 min

Named groups make complex patterns self-documenting and turn matches straight into dicts.

Numbered groups get confusing once a pattern has more than two or three. Named groups fix that:

pat = r"(?P<level>[A-Z]+) (?P<ms>\d+)ms"

Access them by name with m.group("level"), m["level"], or all at once with m.groupdict(), which returns a dict ready to feed into a dataclass or a JSON record. groupdict(default="") replaces None for groups that didn't match. Named groups still have numbers too.

Inside the pattern, refer back to a named group with (?P=name); in re.sub replacements with \g<name>.

Match objects carry more than text:

  • m.start("ms"), m.end(), m.span("level") positions per group
  • m.lastgroup the name of the last matched group, perfect for telling alternatives apart in a tokenizer
  • m.re and m.string the pattern and input
  • m.expand(template) fills a replacement template from the match

A Match object is truthy, and since 3.11 supports m["name"] indexing syntax everywhere.

Combining finditer and groupdict is the most readable way to parse semi-structured lines such as logs into records.

Example

import re

LINE = re.compile(r"(?P<time>\d\d:\d\d) (?P<level>[A-Z]+) (?P<msg>.*)")
log = "10:01 INFO started\n10:02 ERROR disk full\n10:05 INFO done"

records = [m.groupdict() for m in LINE.finditer(log)]
print(records[1])    # {'time': '10:02', 'level': 'ERROR', 'msg': 'disk full'}

m = LINE.search(log)
print(m["level"], m.span("msg"))       # INFO (11, 18)
print(m.expand(r"[\g<level>] \g<msg>"))  # [INFO] started

pair = re.compile(r"(?P<q>['\"])(?P<body>.*?)(?P=q)")
print(pair.search("say 'hi' or \"yo\"")["body"])   # hi

Remember

  • (?P<name>...) names a group; read it with m['name'] or m.groupdict()
  • (?P=name) matches the same text again inside the pattern
  • m.span(name) and m.lastgroup describe where and what matched

Check yourself

  1. What does re.match(r'(?P<k>\w+)=(?P<v>\w*)', 'x=').groupdict() 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.Match.groupdict