A Beginner‘s Guide to Regular Expressions in Python
Regular expressions are a powerful tool for working with text and data in Python. They allow you to define search patterns to extract, modify, and manipulate strings in very flexible ways. While regular expressions (also called regexes) have a reputation for being cryptic, once you understand the basic concepts and syntax, you‘ll find them incredibly useful in a wide range of applications, from data cleaning and validation to web scraping and natural language processing.
In this tutorial, we‘ll introduce the key concepts of regular expressions in Python from the ground up. We‘ll start by covering the basics of the re module and regex syntax, then demonstrate how to actually use regexes to search, match, and transform strings, with plenty of examples. By the end, you‘ll be able to start leveraging regular expressions in your own projects. Let‘s dive in!
The re Module: Python‘s Regex Toolkit
To work with regular expressions in Python, we use the built-in re module. This module provides a set of functions that allow us to define regex patterns and apply them to strings to search, match, and perform various text operations.
Before we get into usage and examples, let‘s first introduce the key functions in the re module:
re.compile(): Compiles a regex pattern into a regex objectre.search(): Searches a string for the first location matching a regex patternre.match(): Matches a regex pattern to the beginning of a stringre.findall(): Finds all substrings in a string that match a patternre.sub(): Substitutes matches in a string with another stringre.split(): Splits a string by the occurrences of a pattern
We‘ll see examples of all of these shortly, but first we need to understand the regex syntax for defining patterns.
Regular Expression Syntax Cheat Sheet
Regular expressions have a compact syntax for specifying patterns in text. Here are the key elements and special characters:
. - Matches any single character except newline ^ - Matches start of string $ - Matches end of string * - Matches 0 or more repetitions of the preceding character + - Matches 1 or more repetitions of the preceding character ? - Matches 0 or 1 repetitions of the preceding character [] - Matches any single character within the brackets [^] - Matches any single character NOT within the brackets | - Matches either the expression before OR after the | () - Defines a group and captures the substring matched by the group
In addition, there are several commonly used shorthand character classes:
d - Matches any decimal digit (same as [0-9]) D - Matches any non-digit character (same as [^0-9]) w - Matches any alphanumeric character (same as [a-zA-Z0-9_]) W - Matches any non-alphanumeric character (same as [^a-zA-Z0-9_]) s - Matches any whitespace character (same as [trnf]) S - Matches any non-whitespace character (same as [^trnf])
We‘ll see many of these in action in the examples throughout the tutorial. Don‘t worry about memorizing it all now – you can always refer back to this cheat sheet.
Searching for Patterns in Strings
The most basic use case for regexes is searching a string to see if it contains a certain pattern. We can do this with re.search().
import retext = "The quick brown fox jumped over the lazy dog" pattern = r"fox"
match = re.search(pattern, text)
if match: print("Found match:", match.group()) else: print("No match found")
This code searches the string text for the literal pattern "fox". The r before the pattern string indicates this is a raw string literal (so backslashes are interpreted literally rather than as escape characters).
If the pattern is found, re.search() returns a match object. We can call methods on this object to get information about the match, like group() which returns the matching text. If no match is found, re.search() returns None.
We can also compile the pattern first using re.compile() and then call methods on the resulting regex object:
pattern = re.compile(r"fox") match = pattern.search(text)
This is useful if you need to apply the same pattern many times.
To find all matches rather than just the first one, use re.findall():
text = "The quick brown fox jumped over the lazy dog fox"matches = re.findall(r"fox", text) print(matches) # [‘fox‘, ‘fox‘]
Matching Strings to Patterns
re.search() finds a match anywhere in the string, but sometimes we want to check if a string matches a pattern from the beginning. For this we use re.match():
pattern = re.compile(r"The")match1 = pattern.match("The quick brown fox") print(bool(match1)) # True
match2 = pattern.match("the quick brown fox") print(bool(match2)) # False
By default, regexes are case-sensitive. To make a pattern case-insensitive, pass the re.I or re.IGNORECASE flag:
pattern = re.compile(r"the", re.I)match = pattern.match("The quick brown fox")
print(bool(match)) # True
Transforming Strings with Regex
In addition to searching, regexes are very useful for modifying and cleaning up text. The re.sub() function allows us to find all matches of a pattern in a string and replace them with something else.
For example, let‘s say we want to replace all occurrences of "fox" with "cat":
text = "The quick brown fox jumped over the lazy dog fox"new_text = re.sub(r"fox", "cat", text) print(new_text) # The quick brown cat jumped over the lazy dog cat
We can also use matched groups in the replacement string by referring to them with backslash and the group number. Here‘s an example that reverses the order of first and last names:
text = "Doe, John and Smith, Jane"print(re.sub(r"(w+),s*(w+)", r"2 1", text)) # John Doe and Jane Smith
The regex (w+),s*(w+) matches a word, a comma, any whitespace, and another word, capturing the words in groups. The replacement r"2 1" refers to these captured groups by number to reverse their order.
Grouping and Capturing
As we saw in the last example, parentheses () not only group parts of a regex together, but also capture the text matched by that group for later reference.
Let‘s say we want to extract all the numbers from a string:
text = "There are 3 apples, 6 oranges, and 10 pears."matches = re.findall(r"(d+)", text) print(matches) # [‘3‘, ‘6‘, ‘10‘]
The regex (d+) matches and captures one or more digits. re.findall() returns a list of all these captured groups.
We can also name our groups by using the syntax (?P<name>...):
text = "John Doe, 123 Main St., Anytown"match = re.search(r"(?P<name>w+s+w+),s+(?P<address>w.*)", text) print(match.group(‘name‘)) # John Doe print(match.group(‘address‘)) # 123 Main St., Anytown
Being able to group and capture parts of a match is a very powerful feature of regexes. It allows us to extract structured data from strings, as we‘ll see more of in the examples below.
Putting It All Together: Real-World Regex Examples
Now that we‘ve covered the basics, let‘s walk through a few more practical, real-world examples of using regular expressions in Python.
Extracting Emails
Let‘s say we have a string that contains email addresses and we want to extract all of them:
text = "For inquiries please contact [email protected] or [email protected]"emails = re.findall(r"[w.-]+@[w.-]+.[a-zA-Z]{2,}", text) print(emails) # [‘[email protected]‘, ‘[email protected]‘]
Here‘s how this regex breaks down:
[w.-]+: Match one or more word characters, dots, or hyphens (for the username)@: Match the @ symbol[w.-]+: Match one or more word characters, dots, or hyphens (for the domain name).: Match a dot[a-zA-Z]{2,}: Match at least 2 letters (for the top-level domain)
Parsing URLs
Here‘s an example of using regexes to parse a URL and extract its components:
url = "https://www.example.com/path/to/page.html?id=123#section1"match = re.search(r"^(?P<protocol>https?)://(?P<domain>[^/]+)(?P<path>/[^?#]+)?(?P<query>?[^#]+)?(?P<fragment>#.*)?$", url)
print(match.group(‘protocol‘)) # https print(match.group(‘domain‘)) # www.example.com print(match.group(‘path‘)) # /path/to/page.html print(match.group(‘query‘)) # ?id=123 print(match.group(‘fragment‘)) # #section1
This complex-looking regex uses named groups to capture the protocol, domain, path, query string, and fragment. The ? after the path, query, and fragment groups makes them optional.
Validating Phone Numbers
Finally, let‘s use a regex to validate a phone number format:
numbers = [
"415-555-1234",
"650-555-2345",
"(416)555-3456",
"202 555 4567",
"4035555678",
"403 555-5679",
"403-555-567",
"(202) 555 5555",
]
pattern = re.compile(r"^(?:(?:d{3})[-.s]?d{3}[-.s]?d{4})?$")
for number in numbers:
match = pattern.match(number)
if match:
print(f"{number} is a valid phone number")
else:
print(f"{number} is not a valid phone number")
This regex uses the following elements:
^and$to match the start and end of the string(?:...)for non-capturing groupsd{3}to match exactly 3 digits[-.s]?to optionally match a dash, dot, or space separator- The final
?to make the entire pattern optional (to allow empty strings)
Tools for Building and Testing Regexes
As you can see, regular expressions can get quite complex! Fortunately, there are many online tools that can help you build and test your patterns. Here are a few:
- Regex101: An online regex tester and debugger with a Python option
- Pythex: A Python-specific regular expression tester with helpful reference
- RegExr: Another online tester with a handy cheatsheet and examples
These tools provide a way to interactively build your regex and see what it matches in real-time. They can be a great help when you‘re learning or when you‘re debugging a tricky pattern.
Conclusion
In this tutorial, we‘ve covered the basics of using regular expressions in Python. We‘ve seen how to define regex patterns, search for these patterns in strings, and use them to match and transform text in various ways. We‘ve also looked at some more advanced concepts like grouping and capturing, and walked through several practical examples.
Regular expressions are a vast topic, and there‘s still much more to learn. But with the fundamentals we‘ve covered here, you‘re well on your way to being able to use regexes effectively in your Python projects. Remember, like any tool, regular expressions are not always the best solution – sometimes simple string methods will suffice. But when you do need the power and flexibility of regexes, they can save you a lot of time and effort.
Here are some key points to remember:
- Use the
remodule to work with regexes in Python - Pass your pattern and string to
re.search(),re.match(),re.findall()orre.sub()depending on your needs - Use
()to group parts of your pattern and capture the matched text - Use character classes like
d,w, andsfor common matching tasks - Use online tools to help you build and test your regexes
To learn more, check out the Python docs on the re module and this regex tutorial on Real Python. And most importantly, practice using regexes in your own code – it‘s the best way to get comfortable with them.
Happy coding!