We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Regex

Before we build the next bit, we need to understand a bit about regexes, or "regular expressions". "Regex" for short, is a programming-language-agnostic way of searching for patterns in text.

They're famous for being hard to read, but occasionally, they are the simplest way to solve a problem.

To get really good at using regex, we'd need a full course on the topic. For now, let's just cover the basics. In Python, we can use the re module to work with regex. It has a findall function that will return a list of all the matches in a string. See examples below.

Regex for a Single Word

import re

text = "I'm a little teapot, short and stout. Here is my handle, here is my spout."
matches = re.findall(r"teapot", text)
print(matches)  # ['teapot']
  • r"teapot" is a regex pattern.
  • The r tells Python to treat the string as a "raw" string, which means we don't have to use escape sequences for backslashes. Escaping in Python involves using a backslash (\) to ensure special characters are treated as literal characters.
  • The pattern teapot will match any exact occurrences of the word "teapot" in the input.

Regex for Phone Number

text = "My phone number is 555-555-5555 and my friend's number is 555-555-5556"
matches = re.findall(r"\d{3}-\d{3}-\d{4}", text)
print(matches)  # ['555-555-5555', '555-555-5556']
  • \d matches any digit
  • {3} means "exactly three of the preceding character"
  • - is just a literal - that we want to match

Regex for Text Between Parentheses

text = "I have a (cat) and a (dog)"
matches = re.findall(r"\((.*?)\)", text)
print(matches)  # ['cat', 'dog']
  • \( and \) are escaped parentheses that we want to match
  • ( and ) is a capture group, meaning it groups the matched text, allowing us to reference or extract it separately.
  • .*? matches any number of characters (except for line terminators) between the parentheses

Regex for Emails Multiple Capture Groups

text = "My email is [email protected] and my friend's email is [email protected]"
matches = re.findall(r"(\w+)@(\w+\.\w+)", text)
print(matches)  # [('lane', 'example.com'), ('hunter', 'example.com')]
  • \w matches any word character (alphanumeric characters and underscores)
  • + means "one or more of the preceding character"
  • @ is just a literal @ symbol that we want to match
  • \. is a literal . that we want to match (The . is a special character in regex, so we escape it with a leading backslash)

Negative Lookbehind

Sometimes you need to match something that is NOT preceded by something else. This is where a negative lookbehind comes in handy.

text = "The word cat appears here, but not in concat"
matches = re.findall(r"(?<!con)cat", text)
print(matches)  # ['cat']
  • (?<!con)cat is a negative lookbehind that matches "cat" only if it's NOT preceded by "con"
  • This allows us to match "cat" but not the "cat" in "concat"
  • The general syntax is (?<!pattern) where pattern is what you don't want to see before your match

Testing Regexes

I love regexr.com for interactive regex testing, it breaks down each part of the pattern and explains what it does.