Python Regex Patterns in Depth
A quantifier says how many times a part may repeat. A group keeps part of a match for reuse.
Repeat with * + and ?
Each quantifier changes how much must appear.
import re
print(re.findall(r"ab*", "a ab abb"))
print(re.findall(r"ab+", "a ab abb"))
print(re.findall(r"colou?r", "color colour"))Repeat a set number of times
Curly braces set a low and high limit.
import re
print(re.findall(r"\d{2,3}", "1 12 123 1234"))Greedy and lazy
Greedy takes the longest match. Lazy takes the shortest match.
import re
print(re.search(r"<.*>", "<b>bold</b>").group())
print(re.search(r"<.*?>", "<b>bold</b>").group())Named groups
A named group lets you read a part by name.
import re
match = re.search(r"(?P<area>\d{3})-(?P<num>\d{4})", "call 555-1234")
print(match.group("area"), match.group("num"))Choose with alternation
The | sign means or inside a pattern.
import re
print(re.findall(r"cat|dog", "I have a cat and a dog"))Replace with a function
re.sub can call a function for each match. The function returns the replacement text.
import re
result = re.sub(r"\d+", lambda m: str(int(m.group()) * 2), "3 cats and 5 dogs")
print(result)Split with a pattern
re.split cuts a string wherever the pattern matches.
import re
print(re.split(r"[,;]", "a,b;c,d"))Example
import re
lines = ["Ann: 555-123-4567", "Bo: (555) 987 6543", "Cy: 555.111.2222"]
def normalise(match):
digits = re.sub(r"\D", "", match.group())
return f"{digits[0:3]}-{digits[3:6]}-{digits[6:10]}"
for line in lines:
print(re.sub(r"\(?\d[\d .()-]*\d", normalise, line))Key points
- Quantifier: a mark that says how many repeats are allowed
- Use * for zero or more, + for one or more, and ? for zero or one
- Use {m,n} for at least m and at most n repeats
- Use (?P<name>...) to give a group a name
- Use | inside a pattern to offer a choice
In this example, each contact line holds one phone number. The outer sub finds the number part in each line. It calls normalise for that match. normalise removes every non-digit with a second sub. It then builds one clean format from the ten digits. Every line prints in the same format.
Note
Greedy matching takes as much text as it can.
Lazy matching with ? takes as little as it can.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Python Playground
Exercise
What does a lazy quantifier like .*? do?