Parentheses capture parts of a match. m.group(1) is the first group, and named groups, (?P<level>\w+), are read with m.group("level") or all at once with m.groupdict().
With groups in the pattern, re.findall returns the groups instead of the whole match: one string per match for one group, a tuple per match for several.
re.sub(pattern, replacement, text) replaces every match. The replacement can refer to groups (r"\1"), or be a function that receives each match and returns the new text.
To validate a whole value, use re.fullmatch: it only succeeds when the pattern covers all of the text. re.match checks only the start, so "555-0142 ext 9" would pass a phone pattern.
Flags change how a pattern reads: re.IGNORECASE ignores capitals, and re.MULTILINE makes ^ and $ work on every line of a long string.