A regular expression can match a whole record while capturing just the pieces you need. The match object’s `group` method retrieves a captured substring by group name: `result.group('last')` gets the surname from a matched name-and-phone record. section 16.4
To extract fields safely:
- Put `(?P<name>...)` around each field you want to retrieve, then pass that name to `group`. section 16.4
- Check whether `search` returned a match before calling `group`; an unmatched line yields `None` instead of a match object. section 16.4
- Allow for optional fields. In the name-and-phone example, `group('middle')` is `None` when the middle name is absent. section 16.4
import re
regexp = re.compile(r"(?P<last>[-a-zA-Z]+)," #1
r" (?P<first>[-a-zA-Z]+)" #2
r"( (?P<middle>([-a-zA-Z]+)))?" #3
r": (?P<phone>((\d{3}-)?\d{3}-\d{4}))" #4
)
file = open("textfile", 'r')
for line in file.readlines():
result = regexp.search(line)
if result == None: #5
print("Oops, I don't think this is a record")
else:
last_name = result.group('last')
first_name = result.group('first')
middle_name = result.group('middle')
if middle_name == None:
middle_name = ""
phone_number = result.group('phone')
print(f"Name: {first_name} {middle_name} {last_name} Number:
{phone_number}")file.close()
The record parser names its surname, first-name, middle-name, and phone captures, then uses `group` to assemble the output. section 16.4
`group` also works inside a replacement function. When `sub` finds a match, it passes the match object to the function; the function can retrieve a capture and return replacement text. section 16.5.1
import re
int_string = "1 2 3 4 5"
def int_match_to_float(match_obj):
return(match_obj.group('num') + ".0")
pattern = r"(?P<num>[0-9]+)"
regexp = re.compile(pattern)
regexp.sub(int_match_to_float, int_string)
'1.0 2.0 3.0 4.0 5.0'
A replacement function calls `match_obj.group('num')` and adds `.0`, changing `1 2 3 4 5` to `1.0 2.0 3.0 4.0 5.0`. section 16.5.1

