Advanced

Pulling fields out

A pattern with named groups turns one line into fields. That is a parser small enough to read, and strict enough to fail on bad input.

What you will see

2

About 2 min of reading

Quick check

Before this new lesson, one small question about the lesson you just finished. Recall it, do not look it up.

Try It

Check what a parse returns.

1

Named field.

import re hit = re.search("(?P\d+):(?P\d+)", "10:45") print(hit.group("m"))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
45
3

Missing field.

import re hit = re.search("(?P\w+)( (?P\w+))?", "solo") print(hit.group("s"))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
None
4

Matches found.

import re print(len(re.findall("(\w+),(\w+)", "a,b c,d")))

Before you run it, say out loud what it will print. Then open the answer.

What it prints
2

Put it in order

Before you write anything, put these lines back in the right order. Click a line to move it up one step. This support step is easier than writing code from scratch, and it is here to make the last example stick.

Data Flow

Named groups fill a mapping when their part matches, and a part that does not run leaves that field as none.
1 match the line
↓
2 fill each named group
↓
3 build the fields
↓
4 report a failed parse
Line by line

Read the first example one line at a time. A line that prints shows what appears on screen; the rest set things up quietly.

import re sets nothing on screen
hit = re.search("(?P<h>\d+):(?P<m>\d+)", "10:45") sets nothing on screen
print(hit.group("m")) 45
Why this works
Named over numbered

Names survive a pattern edit. Numbered groups shift when a bracket is added, and the shift is silent.

None is a field state

An optional group that did not run gives None, not an empty string. A caller that tests truthiness mixes the two.

Examples

Name the parts

import re
hit = re.search("(?P<h>\d+):(?P<m>\d+)", "10:45")
print(hit.group("m"))

A name makes the field readable without counting brackets.

All the fields

import re
hit = re.search("(?P<a>\w+) (?P<b>\w+)", "one two")
print(len(hit.groupdict()))

groupdict gives a mapping of every named group.

Optional field

import re
hit = re.search("(?P<u>\w+)( (?P<s>\w+))?", "solo")
print(hit.group("s"))

An optional group that did not match gives None for that field.

Repeat a field

import re
hits = re.findall("(\w+),(\w+)", "a,b c,d")
print(len(hits))

findall with groups returns one tuple per match.

Bad input fails

import re
hit = re.search("(\d+)-(\d+)", "10 to 45")
print(hit is None)

A missing separator means no match, so the parse reports the failure.

Position of a field

import re
hit = re.search("(\d+)", "ab 12")
print(hit.start(1))

The match object reports where each group began, which is how offsets are found.

← Replacing with a pattern
Previous Lesson
Replacing with a pattern
Next Lesson
Validating a value
Validating a value →