Difficulty: Intermediate
How do you use regular expressions in Python? Explain common patterns.
Python's re module provides regex support for pattern matching in strings.
Key functions: - re.search(): Find first match anywhere in string - re.match(): Match only at the beginning - re.findall(): Find all matches, return as list - re.finditer(): Find all matches, return as iterator of Match objects - re.sub(): Replace matches - re.compile(): Pre-compile pattern for reuse
Common patterns: \d (digit), \w (word char), \s (whitespace), . (any char), * (0+), + (1+), ? (0 or 1), {n,m} (n to m), [] (character class), () (group).
import re
text = "Contact us at support@example.com or sales@company.org"
# search: first match
match = re.search(r'\w+@\w+\.\w+', text)
if match:
print(f"Found: {match.group()}") # support@example.com
print(f"Position: {match.start()}-{match.end()}")
# findall: all matches
emails = re.findall(r'\w+@\w+\.\w+', text)
print(emails) # ['support@example.com', 'sales@company.org']
# match: only at beginning
print(re.match(r'Contact', text)) # Match object
print(re.match(r'support', text)) # None (not at start)
# Common patterns
phone = "Call 123-456-7890 or (987) 654-3210"
phones = re.findall(r'\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}', phone)
print(phones) # ['123-456-7890', '(987) 654-3210']
Use raw strings (r'...') for regex to avoid double-escaping backslashes. search() finds the first match; findall() finds all non-overlapping matches.
import re
# Capturing groups with ()
date_text = "Today is 2024-03-15 and tomorrow is 2024-03-16"
pattern = r'(\d{4})-(\d{2})-(\d{2})'
match = re.search(pattern, date_text)
if match:
print(f"Full match: {match.group(0)}") # 2024-03-15
print(f"Year: {match.group(1)}") # 2024
print(f"Month: {match.group(2)}") # 2024
print(f"Day: {match.group(3)}") # 15
# Named groups (?P<name>...)
pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})'
for match in re.finditer(pattern, date_text):
print(f"{match.group('year')}/{match.group('month')}/{match.group('day')}")
# findall with groups returns tuples
dates = re.findall(pattern, date_text)
print(dates) # [('2024', '03', '15'), ('2024', '03', '16')]
# Non-capturing group (?:...)
words = re.findall(r'(?:Mr|Mrs|Ms)\.\s(\w+)', "Mr. Smith and Mrs. Jones")
print(words) # ['Smith', 'Jones'] - only captures the name
Groups capture parts of the match. Named groups (?P<name>...) make regex more readable. Non-capturing groups (?:...) group without capturing.
import re
# re.sub: find and replace
text = "Hello World, Hello Python"
result = re.sub(r'Hello', 'Hi', text)
print(result) # 'Hi World, Hi Python'
# Substitution with function
def censor(match):
word = match.group()
return word[0] + '*' * (len(word) - 1)
text = "The password is secret123"
result = re.sub(r'\b\w*\d+\w*\b', censor, text)
print(result) # 'The password is s*'
# Compile for reuse (better performance in loops)
email_pattern = re.compile(
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}#39;
)
emails = ['user@example.com', 'bad@', 'test@site.org', 'invalid']
for email in emails:
if email_pattern.match(email):
print(f"Valid: {email}")
else:
print(f"Invalid: {email}")
# Flags
text = "Hello\nhello\nHELLO"
matches = re.findall(r'hello', text, re.IGNORECASE)
print(matches) # ['Hello', 'hello', 'HELLO']
re.compile() pre-compiles the pattern for better performance when reused. re.sub() can take a function as replacement for dynamic substitution.
re module, Pattern Matching, Groups, Substitution, Compilation