Grouping and Capturing with Parentheses
re.search() returns a match object when a pattern is found, or None when no match exists.
A Search Has Two Outcomes
A regular-expression search does not always give back text. When re.search() finds the requested pattern, it returns a match object. When the pattern does not occur in the string, it returns None. That difference is the foundation for understanding grouped and captured search results: first determine whether a match exists, then inspect what the match contains.
What do you think happens?
A search looks for the literal pattern From: in the string Received From: Ada. What kind of result should you expect when the pattern is found?
Reveal answer
Answer: A match object
re.search() returns a match object when it finds a pattern. None indicates that no match exists. The integer -1 is the failure result associated with the string method find(), not re.search().
Following re.search()
The re module provides re.search(). Calling re.search(pattern, string) makes Python scan the string from left to right. As soon as the pattern is found, the search stops and the function returns a match object containing information about the match. If the pattern never appears, the function returns None rather than raising an error.
Treat the result of re.search() as something to test before inspecting it. In a conditional, a match object is truthy and None is falsy, so checking the result first tells you whether it is safe to call methods such as group(), start(), or end().
Reading a Match Object
A match object is the result returned by re.search() when the pattern is found. Its group() method gives the matched text, start() gives the starting index, and end() gives the ending index. The indices use Python's zero-based indexing and slice convention.
Locating From:
Suppose re.search() searches for the literal pattern From: in the string Received From: Ada and returns a match object.
Read the full match: The match object's group() method gives From:, the text matched by the pattern.
Read the start: The first character of From: is at index 9 because Python counts from index 0.
Read the end: The end index is 14, one position after the final character of From:.
Check the slice: The slice from index 9 up to, but not including, index 14 gives the same matched text: From:.
group() gives From:, start() gives 9, and end() gives 14.
Capturing the Exact Span
Capturing is useful because the search result preserves more than a yes-or-no answer. The matched text can be retrieved with group(), while start() and end() identify its location in the original string. Because end() points one position after the final matched character, the same span can be reproduced with string[match.start():match.end()].
If the pattern is absent, the result is None. Calling group(), start(), or end() on None causes an AttributeError. This is why a safe debugging sequence always checks the result before using match-object methods.
Regex or String Method
| Task | Appropriate choice | Failure result | Reason |
|---|---|---|---|
| Search for an exact fixed string | find() or in | find() returns -1; in produces a Boolean result | These methods are simpler for literal text. |
| Search for a pattern involving digits, word characters, repetition, or alternatives | re.search() | None | Regular expressions are intended for patterns that are not simple literals. |
| Check whether text begins with a fixed prefix | startswith() | A false Boolean result | A direct string method expresses this fixed-prefix task. |
Using re.search() for a literal string such as From: works, but it does not demonstrate the main power of regular expressions. For an exact fixed string, line.find('From:') >= 0 or 'From:' in line is simpler. Use re.search() when the pattern involves features such as finding any digit, any word character, repeated text, or one of several alternatives.
Mistakes During Debugging
Calling group() immediately on the result of a search
None is not a match object and has no group() method. The call causes an AttributeError.
Fix:
Check whether the result is truthy or whether it is None before calling group(), start(), or end().Treating re.search() as if it returned only True or False
A Boolean check tells you whether a match exists, but it does not by itself expose the matched text or its positions.
Fix:
Keep the match object when you need group(), start(), or end().Expecting re.search() to return -1 when no match exists
The -1 failure convention belongs to find(). re.search() uses None.
Fix:
Test for None or use the result in a conditional.Using regular expressions for every fixed-string search
The search works, but it does not use the pattern-matching power that makes regular expressions useful.
Fix:
Use find(), in, or startswith() when the task is a simple fixed-string search.
Practice and Transfer
For each situation, decide what result to expect and which information you would inspect: a search finds From: in Received From: Ada; a search does not find From: in Subject: Update; and a program needs to search for any digit rather than one fixed literal string.
Hints
- A successful re.search() produces a match object.
- An unsuccessful re.search() produces None.
- Use group(), start(), and end() to inspect a successful result.
- A pattern involving any digit is a case where regular expressions are more appropriate than a simple literal-string method.
- Identify the pattern and the input string.
- Decide whether the task is a fixed-string search or a pattern search.
- If using re.search(), check whether the result is a match object or None.
- For a match object, inspect group() for the text and start() and end() for its span.
- Remember that the end index is one position after the final matched character.
Working Rules
- re.search() scans from left to right and returns a match object at the first match, or None when no match exists.
- A match object provides the matched text through group(), the starting position through start(), and the ending position through end().
- Python uses zero-based indexing, and string[match.start():match.end()] reproduces the matched text.
- Always check the result before calling match-object methods, because calling them on None causes an AttributeError.
- Use simpler string methods for exact fixed strings, and use re.search() when the task requires a non-literal pattern.
Key Takeaways
- re.search() returns a match object when it finds a pattern and None when it does not.
- The match object's group(), start(), and end() methods reveal the matched text and its position.
- The match span follows Python's zero-based slicing convention.
- Check for a match before calling its methods.
- Prefer simpler string methods for fixed literal searches and re.search() for genuine pattern matching.