Pattern Matching Across Multiple Lines
Parentheses in regular expressions mark the portion of a match that findall() should extract and return.
A Larger Match, A Smaller Result
A regular expression can match a larger piece of text while you keep only a smaller piece of it. Parentheses control this difference. The pattern outside the parentheses must still match, but findall() returns the portion inside the parentheses.
What do you think happens?
Suppose a pattern recognizes a line beginning with X-, followed by a colon and a number, and places parentheses around the number. What should findall() return when the line matches?
Reveal answer
Answer: Only the number inside the parentheses
The complete pattern determines whether the line matches. The parentheses tell findall() which part of that successful match to extract and return.
Matching Versus Capturing
A capturing group is the part of a regular expression enclosed in parentheses. During matching, the parentheses do not change the text that the pattern recognizes. Their special effect appears when findall() constructs its result: instead of returning the entire matched substring, findall() returns the text enclosed by the parentheses.
Keeping Only the Number
A line contains a marker beginning with X-, a colon, and a numeric value. The pattern matches the marker and number together but places parentheses around only the numeric value.
Match: The complete pattern must recognize the required marker, colon, and number before the match succeeds.
Capture: The parentheses identify the numeric portion as the capturing group.
Return: findall() returns a list containing the captured number as a string rather than returning the whole matched text.
The pattern decides whether the text matches; the capturing group decides which part findall() returns.
Parentheses as Extraction Markers
Read a pattern in two layers. First, read all of it as the condition that must match. Then identify the text enclosed in each pair of parentheses. That enclosed text is the part findall() is instructed to keep.
Results Across Multiple Lines
A program can read lines from a file and apply the pattern to each line. For a line that matches, findall() produces a list containing the captured portion. For a line that does not match, findall() produces an empty list, so that line contributes nothing to the printed results.
| Pattern structure | findall() result |
|---|---|
| No capturing group | The entire matched substring |
| One capturing group | A list of strings containing the captured portions |
| Multiple capturing groups | A list of tuples containing captured values in pattern order |
The presence and number of capturing groups determine the structure of the result.
Multiple Groups and Data Types
One capturing group is useful when each match contains one value to keep. You can also place multiple pairs of parentheses in a pattern to extract several parts of the same line. In that case, findall() returns a list of tuples, and each tuple stores the captured values in the order in which their groups appear in the pattern.
Every extracted value begins as a string, even when it looks numeric. If later work requires arithmetic or numeric comparisons, convert the string explicitly to an appropriate type such as int or float.
Extracting Two Values
A matching line contains two pieces of information that are both enclosed in separate capturing groups.
Identify the groups: The first pair of parentheses marks the first value to extract, and the second pair marks the second value.
Read the result shape: Because there are multiple groups, each match is represented as a tuple rather than as one string.
Convert when needed: The captured tuple values are still strings. Convert a numeric value to int or float before using it as a number.
Multiple groups produce tuples, and numeric-looking tuple members remain strings until explicitly converted.
Safe Result Handling
A nonmatching line produces an empty list. Before accessing an element from the result, verify that findall() returned a non-empty list. The source example uses the condition len(x) > 0 so that processing occurs only when a match was found.
Mistakes with Capturing Groups
Expecting findall() to return the entire match when the pattern contains a capturing group.
With a capturing group, findall() returns the captured portion rather than the complete matched substring.
Fix:
Separate the question of whether the pattern matches from the question of which text the parentheses identify for extraction.Treating an extracted numeric-looking value as a number automatically.
findall() returns extracted values as strings.
Fix:
Convert the value explicitly to float or int when numeric operations or comparisons are required.Accessing the first result without checking whether a match exists.
An empty list has no element to access.
Fix:
Verify that the returned list is non-empty, such as by checking len(x) > 0.Assuming multiple capturing groups still produce a simple list of strings.
With multiple groups, findall() returns tuples containing the captured values in pattern order.
Fix:
Handle each result as a tuple and remember that its members are strings until converted.
Practice the Trace
Imagine a multiline input containing several lines. The pattern recognizes lines that begin with X-, contain a colon, and end with a number. Parentheses surround only the number. Predict what findall() returns for a matching line and for a nonmatching line. Then decide whether the returned number is ready for arithmetic or needs conversion.
Hints
- The full pattern decides whether a line matches.
- The parentheses decide which portion is returned.
- A nonmatching line produces an empty list.
- Captured values are strings, even when they look numeric.
Key Takeaways
- The entire regular-expression pattern determines whether text matches.
- Parentheses create capturing groups and tell findall() which matched portions to return.
- One capturing group produces a list of strings; multiple groups produce a list of tuples.
- Extracted values are strings and must be converted to int or float when numeric use is required.
- Check that findall() returned a non-empty list before accessing an element.