You've validated and searched strings with .split(), in, and loops so far — that works, but gets unwieldy fast for anything like "is this a valid email address" or "find every phone number in this text". A regular expression (regex) is a compact pattern language for describing what a string should look like, built into Python's re module.
import re
re.search(r"cat", "the cat sat") # a match object -- found "cat" somewhere in the string
re.search(r"dog", "the cat sat") # None -- not found
The r"..." prefix makes it a raw string — regex patterns use backslashes a lot (\d, \w, \s), and a raw string tells Python not to treat those as its own escape sequences. Always use r"..." for regex patterns.
re.search finds a match anywhere in the string. re.fullmatch requires the entire string to match the pattern — that's usually what you want for validation ("is this whole string a valid email"), as opposed to searching ("does this text contain an email somewhere").
re.fullmatch(r"cat", "cat") # matches -- the whole string is exactly "cat"
re.fullmatch(r"cat", "the cat") # None -- "the cat" isn't ENTIRELY "cat"
| Pattern | Matches |
|---|---|
. |
any single character (except newline) |
\d |
any digit (0-9) |
\w |
any "word" character (letters, digits, underscore) |
\s |
any whitespace character |
^ |
the start of the string |
$ |
the end of the string |
| Pattern | Means |
|---|---|
* |
zero or more of the preceding thing |
+ |
one or more of the preceding thing |
? |
zero or one of the preceding thing (optional) |
{3} |
exactly 3 |
{2,4} |
between 2 and 4 |
re.fullmatch(r"\d+", "12345") # matches -- one or more digits
re.fullmatch(r"\d+", "") # None -- + requires at least one
re.fullmatch(r"\d*", "") # matches -- * allows zero
Combine a character class with a quantifier and you can describe entire shapes of text in one line: \d{3} is exactly 3 digits, \w+ is one or more word characters, and so on. The next lesson builds on this with character sets, groups, and a few more re functions.