Data Validation with Regular Expressions
Parentheses in regular expressions mark the portion of a match that findall() should extract and return.
Matching Versus Keeping
A regular expression can recognize more text than you ultimately want to keep. Parentheses solve this problem by marking the specific portion of a successful match that findall() should extract and return. The surrounding pattern still has to match, but the returned result can be only the text inside the parentheses.
Parentheses do not change which text the pattern matches. They change which part of that match findall() returns.
Tracing findall() Results
What do you think happens?
A pattern matches the text X-:42. If the number is enclosed in parentheses, what will findall() return?
Reveal answer
Answer: Only the text 42
The full pattern must match, but the parentheses identify 42 as the portion to extract. The extracted result is still a string.
Without parentheses, findall() returns the entire substring that matches the pattern. With one capturing group, findall() returns a list containing the strings captured by that group. Therefore, two patterns can match the same text while producing different findall() results.
Parentheses as Capture Boundaries
A capturing group is the part of a regular expression enclosed in parentheses. Text outside the group remains important because it must match for the overall pattern to succeed. However, findall() returns only the text represented by the group. The location of the parentheses in the pattern therefore determines which portion is extracted.
Extracting a Number From a Marked Line
Consider a line with the form X-:42 and a pattern whose number portion is enclosed in parentheses. What does findall() return?
Match the required structure: The line must contain the expected X- prefix, colon, and number. The pattern outside the parentheses participates in this match.
Identify the captured portion: The parentheses surround the number, so the number is the portion selected for extraction.
Read the findall() result: Because there is one capturing group, findall() returns a list of strings containing the captured number rather than the complete line.
The result contains the extracted number as a string, not as an integer.
Multiple Captured Values
A pattern can contain more than one set of parentheses. In that case, findall() returns a list of tuples. Each tuple contains the captured values in the order in which the groups appear in the pattern.
Keeping Two Parts of One Match
Suppose a line contains two portions that a pattern captures with two sets of parentheses. What shape should you expect from findall()?
Match the complete line structure: All required text, including the parts outside the parentheses, must match for the pattern to succeed.
Collect the first group: The first parenthesized portion becomes the first value in the result tuple.
Collect the second group: The second parenthesized portion becomes the second value in the same result tuple.
findall() returns a list of tuples, with captured values ordered by their groups in the pattern.
| Pattern structure | findall() result shape | Returned content |
|---|---|---|
| No capturing group | List | Entire matched substrings |
| One capturing group | List of strings | Only the captured substrings |
| Multiple capturing groups | List of tuples | Captured substrings in group order |
The number of capturing groups changes both the content and structure of findall() results.
Converting Extracted Values
Every value extracted by findall() is a string, even when the characters look like a number. If later work requires arithmetic or comparisons using numeric values, convert the extracted strings explicitly to an appropriate type such as int or float.
Safe Result Handling
Treating the full match as the extracted value
With a capturing group, findall() returns only the portion inside the parentheses.
Fix:
Identify which part of the pattern is enclosed in parentheses and use that as the expected extracted result.Assuming an extracted number already has numeric type
findall() always returns extracted values as strings.
Fix:
Convert the string explicitly when arithmetic or numeric comparison is needed.Accessing a result before checking whether a match occurred
For a nonmatching line, findall() returns an empty list.
Fix:
Verify that the returned list is non-empty before accessing one of its elements.Expecting the same result shape for every number of groups
With multiple groups, findall() returns a list of tuples.
Fix:
Use the number of capturing groups to predict the structure of the result.
When an input line does not match the pattern, findall() returns an empty list. A condition that checks whether the list contains at least one result prevents the program from trying to access a value that is not present.
Practice and Review
For each situation, predict the result shape before writing any processing logic: a pattern with no parentheses, a pattern with one capturing group around the number, and a pattern with two capturing groups. Then decide which extracted values would need conversion before numeric use.
Hints
- Ask whether findall() should return the complete match or only a captured portion.
- Count the sets of parentheses in the pattern.
- Remember that extracted values begin as strings.
- Consider what happens if no input text matches.
- Parentheses define capturing groups in a regular expression. The complete pattern still controls whether a line matches, but findall() returns only the text inside the groups. One group produces a list of strings, while multiple groups produce a list of tuples. Extracted values are strings and may require conversion to int or float. When a line does not match, findall() returns an empty list, so check the result before accessing an element.
Key Takeaways
- A regular expression can match a complete structure while a capturing group selects only the portion to extract.
- findall() returns full matches without capturing groups and captured substrings when groups are present.
- One capturing group produces a list of strings; multiple groups produce a list of tuples.
- Extracted values are always strings and must be converted when another type is needed.
- Check for a non-empty result before accessing extracted values.