Why have regular expressions survived seven decades of technological disruption? Because coders who understand regular expressions have a massive advantage when working with textual data. They can write in a single line of code what takes others dozens!
This article is all about the re.fullmatch(pattern, string) method of Python’s re library. There are three similar methods to help you use regular expressions:
- The findall(pattern, string) method returns a list of string matches. Check out our blog tutorial.
- The search(pattern, string) method returns a match object of the first match. Check out our blog tutorial.
- The match(pattern, string) method returns a match object if the regex matches at the beginning of the string. Check out our blog tutorial.
Related article: Python Regex Superpower – The Ultimate Guide
Do you want to master the regex superpower? Check out my new book The Smartest Way to Learn Regular Expressions in Python with the innovative 3-step approach for active learning: (1) study a book chapter, (2) solve a code puzzle, and (3) watch an educational chapter video.
So how does the
re.fullmatch() method work? Let’s study the specification.
How Does re.fullmatch() Work in Python?
The re.fullmatch(pattern, string) method returns a match object if the pattern matches the whole string.
re.fullmatch(pattern, string, flags=0)
The re.fullmatch() method has up to three arguments.
- pattern: the regular expression pattern that you want to match.
- string: the string which you want to search for the pattern.
- flags (optional argument): a more advanced modifier that allows you to customize the behavior of the function. Want to know how to use those flags? Check out this detailed article on the Finxter blog.
We’ll explore them in more detail later.
The re.fullmatch() method returns a match object. You may ask (and rightly so):
What’s a Match Object?
If a regular expression matches a part of your string, there’s a lot of useful information that comes with it: what’s the exact position of the match? Which regex groups were matched—and where?
The match object is a simple wrapper for this information. Some regex methods of the re package in Python—such as fullmatch()—automatically create a match object upon the first pattern match.
At this point, you don’t need to explore the match object in detail. Just know that we can access the start and end positions of the match in the string by calling the methods m.start() and m.end() on the match object m:
>>> m = re.fullmatch('h...o', 'hello') >>> m.start() 0 >>> m.end() 5
In the first line, you create a match object m by using the re.fullmatch() method. The pattern ‘h…o’ matches in the string ‘hello’ at start position 0 and end position 5. But note that as the fullmatch() method always attempts to match the whole string, the m.start() method will always return zero.
Now, you know the purpose of the match object in Python. Let’s check out a few examples of re.fullmatch()!
A Guided Example for re.fullmatch()
First, you import the re module and create the text string to be searched for the regex patterns:
>>> import re >>> text = ''' Call me Ishmael. Some years ago--never mind how long precisely --having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. '''
Let’s say you want to match the full text with this regular expression:
>>> re.fullmatch('Call(.|\n)*', text) >>>
The first argument is the pattern to be found:
'Call(.|\n)*'. The second argument is the text to be analyzed. You stored the multi-line string in the variable text—so you take this as the second argument. The third argument flags of the fullmatch() method is optional and we skip it in the code.
There’s no output! This means that the re.fullmatch() method did not return a match object. Why? Because at the beginning of the string, there’s no match for the ‘Call’ part of the regex. The regex starts with an empty line!
So how can we fix this? Simple, by matching a new line character ‘\n’ at the beginning of the string.
>>> re.fullmatch('\nCall(.|\n)*', text) <re.Match object; span=(0, 229), match='\nCall me Ishmael. Some years ago--never mind how>
The regex (.|\n)* matches an arbitrary number of characters (new line characters or not) after the prefix ‘\nCall’. This matches the whole text so the result is a match object. Note that there are 229 matching positions so the string included in resulting match object is only the prefix of the whole matching string. This fact is often overlooked by beginner coders.
What’s the Difference Between re.fullmatch() and re.match()?
The methods re.fullmatch() and re.match(pattern, string) both return a match object. Both attempt to match at the beginning of the string. The only difference is that re.fullmatch() also attempts to match the end of the string as well: it wants to match the whole string!
You can see this difference in the following code:
>>> text = 'More with less' >>> re.match('More', text) <re.Match object; span=(0, 4), match='More'> >>> re.fullmatch('More', text) >>>
The re.match(‘More’, text) method matches the string ‘More’ at the beginning of the string ‘More with less’. But the re.fullmatch(‘More’, text) method does not match the whole text. Therefore, it returns the None object—nothing is printed to your shell!
What’s the Difference Between re.fullmatch() and re.findall()?
There are two differences between the re.fullmatch(pattern, string) and re.findall(pattern, string) methods:
- re.fullmatch(pattern, string) returns a match object while re.findall(pattern, string) returns a list of matching strings.
- re.fullmatch(pattern, string) can only match the whole string, while re.findall(pattern, string) can return multiple matches in the string.
Both can be seen in the following example:
>>> text = 'the 42th truth is 42' >>> re.fullmatch('.*?42', text) <re.Match object; span=(0, 20), match='the 42th truth is 42'> >>> re.findall('.*?42', text) ['the 42', 'th truth is 42']
Note that the regex .*? matches an arbitrary number of characters but it attempts to consume as few characters as possible. This is called “non-greedy” match (the *? operator). The fullmatch() method only returns a match object that matches the whole string. The findall() method returns a list of all occurrences. As the match is non-greedy, it finds two such matches.
What’s the Difference Between re.fullmatch() and re.search()?
The methods re.fullmatch() and re.search(pattern, string) both return a match object. However, re.fullmatch() attempts to match the whole string while re.search() matches anywhere in the string.
You can see this difference in the following code:
>>> text = 'Finxter is fun!' >>> re.search('Finxter', text) <re.Match object; span=(0, 7), match='Finxter'> >>> re.fullmatch('Finxter', text) >>>
The re.search() method retrieves the match of the ‘Finxter’ substring as a match object. But the re.fullmatch() method has no return value because the substring ‘Finxter’ does not match the whole string ‘Finxter is fun!’.
How to Use the Optional Flag Argument?
As you’ve seen in the specification, the fullmatch() method comes with an optional third ‘flag’ argument:
re.fullmatch(pattern, string, flags=0)
What’s the purpose of the flags argument?
Flags allow you to control the regular expression engine. Because regular expressions are so powerful, they are a useful way of switching on and off certain features (for example, whether to ignore capitalization when matching your regex).
|re.ASCII||If you don’t use this flag, the special Python regex symbols w, W, b, B, d, D, s and S will match Unicode characters. If you use this flag, those special symbols will match only ASCII characters — as the name suggests.|
|re.A||Same as re.ASCII|
|re.DEBUG||If you use this flag, Python will print some useful information to the shell that helps you debugging your regex.|
|re.IGNORECASE||If you use this flag, the regex engine will perform case-insensitive matching. So if you’re searching for [A-Z], it will also match [a-z].|
|re.I||Same as re.IGNORECASE|
|re.LOCALE||Don’t use this flag — ever. It’s depreciated—the idea was to perform case-insensitive matching depending on your current locale. But it isn’t reliable.|
|re.L||Same as re.LOCALE|
|re.MULTILINE||This flag switches on the following feature: the start-of-the-string regex ‘^’ matches at the beginning of each line (rather than only at the beginning of the string). The same holds for the end-of-the-string regex ‘$’ that now matches also at the end of each line in a multi-line string.|
|re.M||Same as re.MULTILINE|
|re.DOTALL||Without using this flag, the dot regex ‘.’ matches all characters except the newline character ‘n’. Switch on this flag to really match all characters including the newline character.|
|re.S||Same as re.DOTALL|
|re.VERBOSE||To improve the readability of complicated regular expressions, you may want to allow comments and (multi-line) formatting of the regex itself. This is possible with this flag: all whitespace characters and lines that start with the character ‘#’ are ignored in the regex.|
|re.X||Same as re.VERBOSE|
Here’s how you’d use it in a practical example:
>>> text = 'Python is great!' >>> re.search('PYTHON', text, flags=re.IGNORECASE) <re.Match object; span=(0, 6), match='Python'>
Although your regex ‘PYTHON’ is all-caps, we ignore the capitalization by using the flag re.IGNORECASE.
Where to Go From Here?
This article has introduced the re.fullmatch(pattern, string) method that attempts to match the whole string—and returns a match object if it succeeds or None if it doesn’t.
Learning Python is hard. But if you cheat, it isn’t as hard as it has to be: