String Processing
Regular Expression Patterns
Real applications need to validate user input, extract data from logs, and parse structured text. This page provides ready-to-use regex patterns for common tasks: email validation, phone number formatting, URL extraction, and data parsing. These patterns serve as building blocks for text processing pipelines.
Regular expression patterns are reusable solutions for common text matching tasks. This page covers practical patterns for email, phone, URL validation, and text extraction.
Email Patterns
email.py
Replay: real traced execution (multi-file project)
# Email validation patterns
import re
# Email patterns
# Basic email pattern
basic_email = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
emails = [
"user@example.com",
"first.last@domain.co.uk",
"user+tag@example.org",
"invalid@",
"@invalid.com",
"no-at-sign.com",
"user@domain",
"user@domain.c"
]
print("Basic email validation:")
pattern = re.compile(basic_email)
for email in emails:
valid = bool(pattern.match(email))
print(f" {email}: {valid}")
# Extract email parts
email_pattern = r"^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$"
extract_pattern = re.compile(email_pattern)
print("\nExtract email parts:")
test_email = "john.doe@example.com"
match = extract_pattern.match(test_email)
if match:
print(f" Email: {test_email}")
print(f" Username: {match.group(1)}")
print(f" Domain: {match.group(2)}")
print(f" TLD: {match.group(3)}")
# Find all emails in text
text = """
Contact us at support@example.com or sales@company.org.
For urgent matters, email admin@service.net immediately.
"""
find_pattern = re.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
found_emails = find_pattern.findall(text)
print("\nEmails found in text:")
for email in found_emails:
print(f" {email}")
# More strict pattern (requires valid TLD length)
strict_email = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$"
strict_pattern = re.compile(strict_email)
print("\nStrict validation:")
test_emails = [
"user@domain.com",
"user@domain.co",
"user@domain.technology" # 10 chars TLD
]
for email in test_emails:
valid = bool(strict_pattern.match(email))
print(f" {email}: {valid}")
# Named groups
named_pattern = r"^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$"
named_re = re.compile(named_pattern)
match2 = named_re.match("alice@example.com")
if match2:
print("\nNamed groups:")
print(f" Username: {match2.group('username')}")
print(f" Domain: {match2.group('domain')}")
print(f" TLD: {match2.group('tld')}")
# Email validation patterns
import re
# Email patterns
# Basic email pattern
basic_email = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
emails = [
"user@example.com",
"first.last@domain.co.uk",
"user+tag@example.org",
"invalid@",
"@invalid.com",
"no-at-sign.com",
"user@domain",
"user@domain.c"
]
print("Basic email validation:")
pattern = re.compile(basic_email)
for email in emails:
valid = bool(pattern.match(email))
print(f" {email}: {valid}")
# Extract email parts
email_pattern = r"^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$"
extract_pattern = re.compile(email_pattern)
print("\nExtract email parts:")
test_email = "admin@service.net"
match = extract_pattern.match(test_email)
if match:
print(f" Email: {test_email}")
print(f" Username: {match.group(1)}")
print(f" Domain: {match.group(2)}")
print(f" TLD: {match.group(3)}")
# Find all emails in text
text = """
Contact us at support@example.com or sales@company.org.
For urgent matters, email admin@service.net immediately.
"""
find_pattern = re.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
found_emails = find_pattern.findall(text)
print("\nEmails found in text:")
for email in found_emails:
print(f" {email}")
# More strict pattern (requires valid TLD length)
strict_email = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$"
strict_pattern = re.compile(strict_email)
print("\nStrict validation:")
test_emails = [
"user@domain.com",
"user@domain.co",
"user@domain.technology" # 10 chars TLD
]
for email in test_emails:
valid = bool(strict_pattern.match(email))
print(f" {email}: {valid}")
# Named groups
named_pattern = r"^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$"
named_re = re.compile(named_pattern)
match2 = named_re.match("alice@example.com")
if match2:
print("\nNamed groups:")
print(f" Username: {match2.group('username')}")
print(f" Domain: {match2.group('domain')}")
print(f" TLD: {match2.group('tld')}")
# Email validation patterns
import re
# Email patterns
# Basic email pattern
basic_email = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
emails = [
"user@example.com",
"first.last@domain.co.uk",
"user+tag@example.org",
"invalid@",
"@invalid.com",
"no-at-sign.com",
"user@domain",
"user@domain.c"
]
print("Basic email validation:")
pattern = re.compile(basic_email)
for email in emails:
valid = bool(pattern.match(email))
print(f" {email}: {valid}")
# Extract email parts
email_pattern = r"^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$"
extract_pattern = re.compile(email_pattern)
print("\nExtract email parts:")
test_email = "invalid@"
match = extract_pattern.match(test_email)
if match:
print(f" Email: {test_email}")
print(f" Username: {match.group(1)}")
print(f" Domain: {match.group(2)}")
print(f" TLD: {match.group(3)}")
# Find all emails in text
text = """
Contact us at support@example.com or sales@company.org.
For urgent matters, email admin@service.net immediately.
"""
find_pattern = re.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
found_emails = find_pattern.findall(text)
print("\nEmails found in text:")
for email in found_emails:
print(f" {email}")
# More strict pattern (requires valid TLD length)
strict_email = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$"
strict_pattern = re.compile(strict_email)
print("\nStrict validation:")
test_emails = [
"user@domain.com",
"user@domain.co",
"user@domain.technology" # 10 chars TLD
]
for email in test_emails:
valid = bool(strict_pattern.match(email))
print(f" {email}: {valid}")
# Named groups
named_pattern = r"^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$"
named_re = re.compile(named_pattern)
match2 = named_re.match("alice@example.com")
if match2:
print("\nNamed groups:")
print(f" Username: {match2.group('username')}")
print(f" Domain: {match2.group('domain')}")
print(f" TLD: {match2.group('tld')}")
basic_email ← ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
6# Basic email pattern7basic_email→ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"89emails→ ['user@example.com', 'first.last@domain.co.uk', 'user+tag@example.org', 'invalid@', '@invalid.com', 'no-at-sign.com', 'user@domain', 'user@domain.c'] = [10 "user@example.com",11 "first.last@domain.co.uk",12 "user+tag@example.org",13 "invalid@",14 "@invalid.com",15 "no-at-sign.com",16 "user@domain",17 "user@domain.c"18]1920print("Basic email validation:")21pattern→ re.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(basic_email^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$)22for email in emails:outputBasic email validation:valid ← True
pass 1 of 821pattern = re.compile(basic_email)22for emailuser@example.com in emails['user@example.com', 'first.last@domain.co.uk', 'user+tag@example.org', 'invalid@', '@invalid.com', 'no-at-sign.com', 'user@domain', 'user@domain.c']:23 valid→ True = bool(patternre.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$').match(emailuser@example.com))24 print(f" {emailuser@example.com}: {validTrue}")output user@example.com: TrueAll 8 passes — pass 1 is the card above pass emailvalid1 user@example.com True 2 first.last@domain.co.uk True 3 user+tag@example.org True 4 invalid@ False 5 @invalid.com False 6 no-at-sign.com False 7 user@domain False 8 user@domain.c False email_pattern ← ^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$
26# Extract email parts27email_pattern→ ^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$ = r"^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$"28extract_pattern→ re.compile('^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\\.([a-zA-Z]{2,})$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(email_pattern^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$)2930print("\nExtract email parts:")31test_email→ john.doe@example.com = "john.doe@example.com"32#@test_email="admin@service.net", "invalid@"33match→ <re.Match object; span=(0, 20), match='john.doe@example.com'> = extract_patternre.compile('^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\\.([a-zA-Z]{2,})$').match(test_emailjohn.doe@example.com)output Extract email parts:if match:
35if match<re.Match object; span=(0, 20), match='john.doe@example.com'>:36 print(f" Email: {test_emailjohn.doe@example.com}")37 print(f" Username: {match<re.Match object; span=(0, 20), match='john.doe@example.com'>.group(1)}")38 print(f" Domain: {match<re.Match object; span=(0, 20), match='john.doe@example.com'>.group(2)}")39 print(f" TLD: {match<re.Match object; span=(0, 20), match='john.doe@example.com'>.group(3)}")output Email: john.doe@example.com Username: john.doe Domain: example TLD: comtext ← Contact us at support@example.com or sales@company.org. For urgent matters, email admin@service.net immediately.
41# Find all emails in text42text→ Contact us at support@example.com or sales@company.org. For urgent matters, email admin@service.net immediately. = """43Contact us at support@example.com or sales@company.org.44For urgent matters, email admin@service.net immediately.45"""4647find_pattern→ re.compile('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")48found_emails→ ['support@example.com', 'sales@company.org', 'admin@service.net'] = find_patternre.compile('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}').findall(text Contact us at support@example.com or sales@company.org. For urgent matters, email admin@service.net immediately. )4950print("\nEmails found in text:")51for email in found_emails:output Emails found in text:for email in found_emails:
pass 1 of 350print("\nEmails found in text:")51for emailsupport@example.com in found_emails['support@example.com', 'sales@company.org', 'admin@service.net']:52 print(f" {emailsupport@example.com}")output support@example.comAll 3 passes — pass 1 is the card above pass email1 support@example.com 2 sales@company.org 3 admin@service.net strict_email ← ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$
54# More strict pattern (requires valid TLD length)55strict_email→ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$ = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$"56strict_pattern→ re.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(strict_email^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$)5758print("\nStrict validation:")59test_emails→ ['user@domain.com', 'user@domain.co', 'user@domain.technology'] = [60 "user@domain.com",61 "user@domain.co",62 "user@domain.technology" # 10 chars TLD63]output Strict validation:valid ← True
pass 1 of 365for emailuser@domain.com in test_emails['user@domain.com', 'user@domain.co', 'user@domain.technology']:66 valid→ True = bool(strict_patternre.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$').match(emailuser@domain.com))67 print(f" {emailuser@domain.com}: {validTrue}")output user@domain.com: TrueAll 3 passes — pass 1 is the card above pass emailvalid1 user@domain.com True 2 user@domain.co True 3 user@domain.technology False named_pattern ← ^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$
69# Named groups70named_pattern→ ^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$ = r"^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$"71named_re→ re.compile('^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\\.(?P<tld>[a-zA-Z]{2,})$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(named_pattern^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$)7273match2→ <re.Match object; span=(0, 17), match='alice@example.com'> = named_rere.compile('^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\\.(?P<tld>[a-zA-Z]{2,})$').match("alice@example.com")74if match2:if match2:
73match2 = named_re.match("alice@example.com")74if match2<re.Match object; span=(0, 17), match='alice@example.com'>:75 print("\nNamed groups:")76 print(f" Username: {match2<re.Match object; span=(0, 17), match='alice@example.com'>.group('username')}")77 print(f" Domain: {match2<re.Match object; span=(0, 17), match='alice@example.com'>.group('domain')}")78 print(f" TLD: {match2<re.Match object; span=(0, 17), match='alice@example.com'>.group('tld')}")output Named groups: Username: alice Domain: example TLD: com
basic_email ← ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
6# Basic email pattern7basic_email→ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"89emails→ ['user@example.com', 'first.last@domain.co.uk', 'user+tag@example.org', 'invalid@', '@invalid.com', 'no-at-sign.com', 'user@domain', 'user@domain.c'] = [10 "user@example.com",11 "first.last@domain.co.uk",12 "user+tag@example.org",13 "invalid@",14 "@invalid.com",15 "no-at-sign.com",16 "user@domain",17 "user@domain.c"18]1920print("Basic email validation:")21pattern→ re.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(basic_email^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$)22for email in emails:outputBasic email validation:valid ← True
pass 1 of 821pattern = re.compile(basic_email)22for emailuser@example.com in emails['user@example.com', 'first.last@domain.co.uk', 'user+tag@example.org', 'invalid@', '@invalid.com', 'no-at-sign.com', 'user@domain', 'user@domain.c']:23 valid→ True = bool(patternre.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$').match(emailuser@example.com))24 print(f" {emailuser@example.com}: {validTrue}")output user@example.com: TrueAll 8 passes — pass 1 is the card above pass emailvalid1 user@example.com True 2 first.last@domain.co.uk True 3 user+tag@example.org True 4 invalid@ False 5 @invalid.com False 6 no-at-sign.com False 7 user@domain False 8 user@domain.c False email_pattern ← ^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$
26# Extract email parts27email_pattern→ ^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$ = r"^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$"28extract_pattern→ re.compile('^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\\.([a-zA-Z]{2,})$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(email_pattern^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$)2930print("\nExtract email parts:")31test_email→ admin@service.net = "admin@service.net"32match→ <re.Match object; span=(0, 17), match='admin@service.net'> = extract_patternre.compile('^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\\.([a-zA-Z]{2,})$').match(test_emailadmin@service.net)output Extract email parts:if match:
34if match<re.Match object; span=(0, 17), match='admin@service.net'>:35 print(f" Email: {test_emailadmin@service.net}")36 print(f" Username: {match<re.Match object; span=(0, 17), match='admin@service.net'>.group(1)}")37 print(f" Domain: {match<re.Match object; span=(0, 17), match='admin@service.net'>.group(2)}")38 print(f" TLD: {match<re.Match object; span=(0, 17), match='admin@service.net'>.group(3)}")output Email: admin@service.net Username: admin Domain: service TLD: nettext ← Contact us at support@example.com or sales@company.org. For urgent matters, email admin@service.net immediately.
40# Find all emails in text41text→ Contact us at support@example.com or sales@company.org. For urgent matters, email admin@service.net immediately. = """42Contact us at support@example.com or sales@company.org.43For urgent matters, email admin@service.net immediately.44"""4546find_pattern→ re.compile('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")47found_emails→ ['support@example.com', 'sales@company.org', 'admin@service.net'] = find_patternre.compile('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}').findall(text Contact us at support@example.com or sales@company.org. For urgent matters, email admin@service.net immediately. )4849print("\nEmails found in text:")50for email in found_emails:output Emails found in text:for email in found_emails:
pass 1 of 349print("\nEmails found in text:")50for emailsupport@example.com in found_emails['support@example.com', 'sales@company.org', 'admin@service.net']:51 print(f" {emailsupport@example.com}")output support@example.comAll 3 passes — pass 1 is the card above pass email1 support@example.com 2 sales@company.org 3 admin@service.net strict_email ← ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$
53# More strict pattern (requires valid TLD length)54strict_email→ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$ = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$"55strict_pattern→ re.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(strict_email^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$)5657print("\nStrict validation:")58test_emails→ ['user@domain.com', 'user@domain.co', 'user@domain.technology'] = [59 "user@domain.com",60 "user@domain.co",61 "user@domain.technology" # 10 chars TLD62]output Strict validation:valid ← True
pass 1 of 364for emailuser@domain.com in test_emails['user@domain.com', 'user@domain.co', 'user@domain.technology']:65 valid→ True = bool(strict_patternre.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$').match(emailuser@domain.com))66 print(f" {emailuser@domain.com}: {validTrue}")output user@domain.com: TrueAll 3 passes — pass 1 is the card above pass emailvalid1 user@domain.com True 2 user@domain.co True 3 user@domain.technology False named_pattern ← ^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$
68# Named groups69named_pattern→ ^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$ = r"^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$"70named_re→ re.compile('^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\\.(?P<tld>[a-zA-Z]{2,})$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(named_pattern^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$)7172match2→ <re.Match object; span=(0, 17), match='alice@example.com'> = named_rere.compile('^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\\.(?P<tld>[a-zA-Z]{2,})$').match("alice@example.com")73if match2:if match2:
72match2 = named_re.match("alice@example.com")73if match2<re.Match object; span=(0, 17), match='alice@example.com'>:74 print("\nNamed groups:")75 print(f" Username: {match2<re.Match object; span=(0, 17), match='alice@example.com'>.group('username')}")76 print(f" Domain: {match2<re.Match object; span=(0, 17), match='alice@example.com'>.group('domain')}")77 print(f" TLD: {match2<re.Match object; span=(0, 17), match='alice@example.com'>.group('tld')}")output Named groups: Username: alice Domain: example TLD: com
basic_email ← ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
6# Basic email pattern7basic_email→ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"89emails→ ['user@example.com', 'first.last@domain.co.uk', 'user+tag@example.org', 'invalid@', '@invalid.com', 'no-at-sign.com', 'user@domain', 'user@domain.c'] = [10 "user@example.com",11 "first.last@domain.co.uk",12 "user+tag@example.org",13 "invalid@",14 "@invalid.com",15 "no-at-sign.com",16 "user@domain",17 "user@domain.c"18]1920print("Basic email validation:")21pattern→ re.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(basic_email^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$)22for email in emails:outputBasic email validation:valid ← True
pass 1 of 821pattern = re.compile(basic_email)22for emailuser@example.com in emails['user@example.com', 'first.last@domain.co.uk', 'user+tag@example.org', 'invalid@', '@invalid.com', 'no-at-sign.com', 'user@domain', 'user@domain.c']:23 valid→ True = bool(patternre.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$').match(emailuser@example.com))24 print(f" {emailuser@example.com}: {validTrue}")output user@example.com: TrueAll 8 passes — pass 1 is the card above pass emailvalid1 user@example.com True 2 first.last@domain.co.uk True 3 user+tag@example.org True 4 invalid@ False 5 @invalid.com False 6 no-at-sign.com False 7 user@domain False 8 user@domain.c False email_pattern ← ^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$
26# Extract email parts27email_pattern→ ^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$ = r"^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$"28extract_pattern→ re.compile('^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\\.([a-zA-Z]{2,})$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(email_pattern^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})$)2930print("\nExtract email parts:")31test_email→ invalid@ = "invalid@"32match→ None = extract_patternre.compile('^([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\\.([a-zA-Z]{2,})$').match(test_emailinvalid@)3334if match:35 print(f" Email: {test_email}")36 print(f" Username: {match.group(1)}")37 print(f" Domain: {match.group(2)}")38 print(f" TLD: {match.group(3)}")3940# Find all emails in text41text→ Contact us at support@example.com or sales@company.org. For urgent matters, email admin@service.net immediately. = """42Contact us at support@example.com or sales@company.org.43For urgent matters, email admin@service.net immediately.44"""4546find_pattern→ re.compile('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")47found_emails→ ['support@example.com', 'sales@company.org', 'admin@service.net'] = find_patternre.compile('[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}').findall(text Contact us at support@example.com or sales@company.org. For urgent matters, email admin@service.net immediately. )4849print("\nEmails found in text:")50for email in found_emails:output Extract email parts: Emails found in text:for email in found_emails:
pass 1 of 349print("\nEmails found in text:")50for emailsupport@example.com in found_emails['support@example.com', 'sales@company.org', 'admin@service.net']:51 print(f" {emailsupport@example.com}")output support@example.comAll 3 passes — pass 1 is the card above pass email1 support@example.com 2 sales@company.org 3 admin@service.net strict_email ← ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$
53# More strict pattern (requires valid TLD length)54strict_email→ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$ = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$"55strict_pattern→ re.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(strict_email^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6}$)5657print("\nStrict validation:")58test_emails→ ['user@domain.com', 'user@domain.co', 'user@domain.technology'] = [59 "user@domain.com",60 "user@domain.co",61 "user@domain.technology" # 10 chars TLD62]output Strict validation:valid ← True
pass 1 of 364for emailuser@domain.com in test_emails['user@domain.com', 'user@domain.co', 'user@domain.technology']:65 valid→ True = bool(strict_patternre.compile('^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$').match(emailuser@domain.com))66 print(f" {emailuser@domain.com}: {validTrue}")output user@domain.com: TrueAll 3 passes — pass 1 is the card above pass emailvalid1 user@domain.com True 2 user@domain.co True 3 user@domain.technology False named_pattern ← ^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$
68# Named groups69named_pattern→ ^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$ = r"^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$"70named_re→ re.compile('^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\\.(?P<tld>[a-zA-Z]{2,})$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(named_pattern^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\.(?P<tld>[a-zA-Z]{2,})$)7172match2→ <re.Match object; span=(0, 17), match='alice@example.com'> = named_rere.compile('^(?P<username>[a-zA-Z0-9._%+-]+)@(?P<domain>[a-zA-Z0-9.-]+)\\.(?P<tld>[a-zA-Z]{2,})$').match("alice@example.com")73if match2:if match2:
72match2 = named_re.match("alice@example.com")73if match2<re.Match object; span=(0, 17), match='alice@example.com'>:74 print("\nNamed groups:")75 print(f" Username: {match2<re.Match object; span=(0, 17), match='alice@example.com'>.group('username')}")76 print(f" Domain: {match2<re.Match object; span=(0, 17), match='alice@example.com'>.group('domain')}")77 print(f" TLD: {match2<re.Match object; span=(0, 17), match='alice@example.com'>.group('tld')}")output Named groups: Username: alice Domain: example TLD: com
email_pattern
Pattern for validating and extracting email addresses
Phone Patterns
phone.py
Replay: real traced execution (multi-file project)
# Phone number patterns
import re
# Phone patterns
# US phone formats
patterns = [
r"\(\d{3}\)\s\d{3}-\d{4}", # (123) 456-7890
r"\d{3}-\d{3}-\d{4}", # 123-456-7890
r"\d{10}" # 1234567890
]
phones = [
"(555) 123-4567",
"555-123-4567",
"5551234567",
"(555)123-4567", # no space
"555.123.4567",
"invalid"
]
print("Phone validation:")
for i, pattern_str in enumerate(patterns, 1):
print(f"\nPattern {i}:")
p = re.compile(pattern_str)
for phone in phones:
valid = bool(p.fullmatch(phone))
print(f" {phone}: {valid}")
# Combined pattern (any format)
any_format = r"^(\(\d{3}\)\s?|\d{3}-)?\d{3}-?\d{4}$"
any_pattern = re.compile(any_format)
print("\nCombined pattern:")
for phone in phones:
valid = bool(any_pattern.match(phone))
print(f" {phone}: {valid}")
# Extract phone parts
extract_pattern = r"\((\d{3})\)\s(\d{3})-(\d{4})"
extract = re.compile(extract_pattern)
test_phone = "(555) 123-4567"
match = extract.match(test_phone)
if match:
print(f"\nExtracted parts from {test_phone}:")
print(f" Area code: {match.group(1)}")
print(f" Exchange: {match.group(2)}")
print(f" Number: {match.group(3)}")
# Find all phones in text
text = """
Call us at (555) 123-4567 or 555-987-6543.
Emergency: (999) 911-0000
"""
find_pattern = re.compile(r"\(?\d{3}\)?[-\s]?\d{3}-\d{4}")
found = find_pattern.findall(text)
print("\nPhones found in text:")
for phone in found:
print(f" {phone}")
# International format (basic)
intl_pattern = r"^\+?\d{1,3}[-\s]?\(?\d{1,4}\)?[-\s]?\d{1,4}[-\s]?\d{1,9}$"
intl_p = re.compile(intl_pattern)
intl_phones = [
"+1 (555) 123-4567",
"+44 20 7123 4567",
"+81 3-1234-5678"
]
print("\nInternational phones:")
for phone in intl_phones:
valid = bool(intl_p.match(phone))
print(f" {phone}: {valid}")
# Format phone number
def format_phone(digits):
"""Convert 10 digits to (XXX) XXX-XXXX format"""
if len(digits) == 10 and digits.isdigit():
return f"({digits[:3]}) {digits[3:6]}-{digits[6:]}"
return None
print("\nFormat phone:")
raw = "5551234567"
formatted = format_phone(raw)
print(f" {raw} -> {formatted}")
patterns ← ['\\(\\d{3}\\)\\s\\d{3}-\\d{4}', '\\d{3}-\\d{3}-\\d{4}', '\\d{10}']
6# US phone formats7patterns→ ['\\(\\d{3}\\)\\s\\d{3}-\\d{4}', '\\d{3}-\\d{3}-\\d{4}', '\\d{10}'] = [8 r"\(\d{3}\)\s\d{3}-\d{4}", # (123) 456-78909 r"\d{3}-\d{3}-\d{4}", # 123-456-789010 r"\d{10}" # 123456789011]1213phones→ ['(555) 123-4567', '555-123-4567', '5551234567', '(555)123-4567', '555.123.4567', 'invalid'] = [14 "(555) 123-4567",15 "555-123-4567",16 "5551234567",17 "(555)123-4567", # no space18 "555.123.4567",19 "invalid"20]2122print("Phone validation:")23for i, pattern_str in enumerate(patterns, 1):outputPhone validation:p ← re.compile('\\(\\d{3}\\)\\s\\d{3}-\\d{4}')
pass 1 of 322print("Phone validation:")23for i1, pattern_str\(\d{3}\)\s\d{3}-\d{4} in enumerate(patterns['\\(\\d{3}\\)\\s\\d{3}-\\d{4}', '\\d{3}-\\d{3}-\\d{4}', '\\d{10}'], 1):24 print(f"\nPattern {i1}:")25 p→ re.compile('\\(\\d{3}\\)\\s\\d{3}-\\d{4}') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(pattern_str\(\d{3}\)\s\d{3}-\d{4})26 for phone in phones:output Pattern 1:All 3 passes — pass 1 is the card above pass ipattern_strp1 1 \(\d{3}\)\s\d{3}-\d{4} re.compile('\\(\\d{3}\\)\\s\\d{3}-\\d{4}') 2 2 \d{3}-\d{3}-\d{4} re.compile('\\d{3}-\\d{3}-\\d{4}') 3 3 \d{10} re.compile('\\d{10}') valid ← True
pass 1 of 1825p = re.compile(pattern_str)26for phone(555) 123-4567 in phones['(555) 123-4567', '555-123-4567', '5551234567', '(555)123-4567', '555.123.4567', 'invalid']:27 valid→ True = bool(pre.compile('\\(\\d{3}\\)\\s\\d{3}-\\d{4}').fullmatch(phone(555) 123-4567))28 print(f" {phone(555) 123-4567}: {validTrue}")output (555) 123-4567: True18 passes — pass 1 is the card above pass phonepvalid1 (555) 123-4567 re.compile('\\(\\d{3}\\)\\s\\d{3}-\\d{4}') True 2 555-123-4567 re.compile('\\(\\d{3}\\)\\s\\d{3}-\\d{4}') False 3 5551234567 re.compile('\\(\\d{3}\\)\\s\\d{3}-\\d{4}') False 4 (555)123-4567 re.compile('\\(\\d{3}\\)\\s\\d{3}-\\d{4}') False 5 555.123.4567 re.compile('\\(\\d{3}\\)\\s\\d{3}-\\d{4}') False 6 invalid re.compile('\\(\\d{3}\\)\\s\\d{3}-\\d{4}') False 7 (555) 123-4567 re.compile('\\d{3}-\\d{3}-\\d{4}') False 8 555-123-4567 re.compile('\\d{3}-\\d{3}-\\d{4}') True 9 5551234567 re.compile('\\d{3}-\\d{3}-\\d{4}') False ⋯ 7 more passes ⋯ 17 555.123.4567 re.compile('\\d{10}') False 18 invalid re.compile('\\d{10}') False any_format ← ^(\(\d{3}\)\s?|\d{3}-)?\d{3}-?\d{4}$, any_pattern ← re.compile('^(\\(\\d{3}\\)\\s?|\\d{3}-)?\\d{3}-?\\d{4}$')
30# Combined pattern (any format)31any_format→ ^(\(\d{3}\)\s?|\d{3}-)?\d{3}-?\d{4}$ = r"^(\(\d{3}\)\s?|\d{3}-)?\d{3}-?\d{4}$"32any_pattern→ re.compile('^(\\(\\d{3}\\)\\s?|\\d{3}-)?\\d{3}-?\\d{4}$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(any_format^(\(\d{3}\)\s?|\d{3}-)?\d{3}-?\d{4}$)3334print("\nCombined pattern:")35for phone in phones:output Combined pattern:valid ← True
pass 1 of 634print("\nCombined pattern:")35for phone(555) 123-4567 in phones['(555) 123-4567', '555-123-4567', '5551234567', '(555)123-4567', '555.123.4567', 'invalid']:36 valid→ True = bool(any_patternre.compile('^(\\(\\d{3}\\)\\s?|\\d{3}-)?\\d{3}-?\\d{4}$').match(phone(555) 123-4567))37 print(f" {phone(555) 123-4567}: {validTrue}")output (555) 123-4567: TrueAll 6 passes — pass 1 is the card above pass phonevalid1 (555) 123-4567 True 2 555-123-4567 True 3 5551234567 False 4 (555)123-4567 True 5 555.123.4567 False 6 invalid False extract_pattern ← \((\d{3})\)\s(\d{3})-(\d{4}), extract ← re.compile('\\((\\d{3})\\)\\s(\\d{3})-(\\d{4})')
39# Extract phone parts40extract_pattern→ \((\d{3})\)\s(\d{3})-(\d{4}) = r"\((\d{3})\)\s(\d{3})-(\d{4})"41extract→ re.compile('\\((\\d{3})\\)\\s(\\d{3})-(\\d{4})') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(extract_pattern\((\d{3})\)\s(\d{3})-(\d{4}))4243test_phone→ (555) 123-4567 = "(555) 123-4567"44match→ <re.Match object; span=(0, 14), match='(555) 123-4567'> = extractre.compile('\\((\\d{3})\\)\\s(\\d{3})-(\\d{4})').match(test_phone(555) 123-4567)if match:
46if match<re.Match object; span=(0, 14), match='(555) 123-4567'>:47 print(f"\nExtracted parts from {test_phone(555) 123-4567}:")48 print(f" Area code: {match<re.Match object; span=(0, 14), match='(555) 123-4567'>.group(1)}")49 print(f" Exchange: {match<re.Match object; span=(0, 14), match='(555) 123-4567'>.group(2)}")50 print(f" Number: {match<re.Match object; span=(0, 14), match='(555) 123-4567'>.group(3)}")output Extracted parts from (555) 123-4567: Area code: 555 Exchange: 123 Number: 4567text ← Call us at (555) 123-4567 or 555-987-6543. Emergency: (999) 911-0000
52# Find all phones in text53text→ Call us at (555) 123-4567 or 555-987-6543. Emergency: (999) 911-0000 = """54Call us at (555) 123-4567 or 555-987-6543.55Emergency: (999) 911-000056"""5758find_pattern→ re.compile('\\(?\\d{3}\\)?[-\\s]?\\d{3}-\\d{4}') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"\(?\d{3}\)?[-\s]?\d{3}-\d{4}")59found→ ['(555) 123-4567', '555-987-6543', '(999) 911-0000'] = find_patternre.compile('\\(?\\d{3}\\)?[-\\s]?\\d{3}-\\d{4}').findall(text Call us at (555) 123-4567 or 555-987-6543. Emergency: (999) 911-0000 )6061print("\nPhones found in text:")62for phone in found:output Phones found in text:for phone in found:
pass 1 of 361print("\nPhones found in text:")62for phone(555) 123-4567 in found['(555) 123-4567', '555-987-6543', '(999) 911-0000']:63 print(f" {phone(555) 123-4567}")output (555) 123-4567All 3 passes — pass 1 is the card above pass phone1 (555) 123-4567 2 555-987-6543 3 (999) 911-0000 intl_pattern ← ^\+?\d{1,3}[-\s]?\(?\d{1,4}\)?[-\s]?\d{1,4}[-\s]?\d{1,9}$
65# International format (basic)66intl_pattern→ ^\+?\d{1,3}[-\s]?\(?\d{1,4}\)?[-\s]?\d{1,4}[-\s]?\d{1,9}$ = r"^\+?\d{1,3}[-\s]?\(?\d{1,4}\)?[-\s]?\d{1,4}[-\s]?\d{1,9}$"67intl_p→ re.compile('^\\+?\\d{1,3}[-\\s]?\\(?\\d{1,4}\\)?[-\\s]?\\d{1,4}[-\\s]?\\d{1,9}$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(intl_pattern^\+?\d{1,3}[-\s]?\(?\d{1,4}\)?[-\s]?\d{1,4}[-\s]?\d{1,9}$)6869intl_phones→ ['+1 (555) 123-4567', '+44 20 7123 4567', '+81 3-1234-5678'] = [70 "+1 (555) 123-4567",71 "+44 20 7123 4567",72 "+81 3-1234-5678"73]7475print("\nInternational phones:")76for phone in intl_phones:output International phones:valid ← True
pass 1 of 375print("\nInternational phones:")76for phone+1 (555) 123-4567 in intl_phones['+1 (555) 123-4567', '+44 20 7123 4567', '+81 3-1234-5678']:77 valid→ True = bool(intl_pre.compile('^\\+?\\d{1,3}[-\\s]?\\(?\\d{1,4}\\)?[-\\s]?\\d{1,4}[-\\s]?\\d{1,9}$').match(phone+1 (555) 123-4567))78 print(f" {phone+1 (555) 123-4567}: {validTrue}")output +1 (555) 123-4567: TrueAll 3 passes — pass 1 is the card above pass phonevalid1 +1 (555) 123-4567 True 2 +44 20 7123 4567 True 3 +81 3-1234-5678 True raw ← 5551234567
87print("\nFormat phone:")88raw→ 5551234567 = "5551234567"89formatted = format_phone(raw5551234567)90print(f" {raw} -> {formatted}")output Format phone:def format_phone(digits):
80# Format phone number81def format_phone(digits5551234567):82 """Convert 10 digits to (XXX) XXX-XXXX format"""83 if len(digits) == 10 and digits.isdigit():if len(digits) == 10 and digits.isdigit():
82"""Convert 10 digits to (XXX) XXX-XXXX format"""83if len(digits5551234567) == 10 and digits.isdigit():84 return f"({digits[:3]555}) {digits[3:6]123}-{digits[6:]4567}"85return Noneformatted ← (555) 123-4567
88raw = "5551234567"89formatted→ (555) 123-4567 = format_phone(raw5551234567)90print(f" {raw5551234567} -> {formatted(555) 123-4567}")output 5551234567 -> (555) 123-4567
phone_pattern
Patterns for various phone number formats including international
URL Patterns
url.py
Replay: real traced execution (multi-file project)
# URL patterns
import re
# URL patterns
# Basic URL pattern
url_pattern = r"^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}.*$"
urls = [
"https://example.com",
"http://www.example.com",
"https://sub.example.co.uk",
"https://example.com/path",
"https://example.com/path?key=value",
"ftp://example.com", # wrong protocol
"example.com", # missing protocol
"https://localhost" # no TLD
]
print("URL validation:")
pattern = re.compile(url_pattern)
for url in urls:
valid = bool(pattern.match(url))
print(f" {url}: {valid}")
# Extract URL parts
extract_pattern = r"^(https?)://([a-zA-Z0-9.-]+)(/.*)? $"
extract_p = re.compile(extract_pattern)
test_url = "https://www.example.com/path/to/page"
match = extract_p.match(test_url)
if match:
print(f"\nExtracted parts from {test_url}:")
print(f" Protocol: {match.group(1)}")
print(f" Domain: {match.group(2)}")
print(f" Path: {match.group(3) if match.group(3) else '/'}")
# More detailed extraction
detail_pattern = r"^(https?)://([^:/]+)(?::(\d+))?(/.*)?$"
detail_p = re.compile(detail_pattern)
test_urls = [
"https://example.com:8080/path",
"http://localhost:3000/api",
"https://example.com/page"
]
print("\nDetailed URL parsing:")
for url in test_urls:
m = detail_p.match(url)
if m:
print(f" {url}")
print(f" Protocol: {m.group(1)}")
print(f" Host: {m.group(2)}")
print(f" Port: {m.group(3) if m.group(3) else 'default'}")
print(f" Path: {m.group(4) if m.group(4) else '/'}")
# Find all URLs in text
text = """
Visit https://example.com for more info.
Check out http://test.org/page and https://another.site/path?q=search
"""
find_pattern = re.compile(r"https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}[^\s]*")
found = find_pattern.findall(text)
print("\nURLs found in text:")
for url in found:
print(f" {url}")
# Query parameters
query_pattern = r"[?&]([^=]+)=([^&]+)"
url_with_query = "https://example.com/search?q=regex&lang=python&page=1"
query_p = re.compile(query_pattern)
params = query_p.findall(url_with_query)
print(f"\nQuery parameters from: {url_with_query}")
for key, value in params:
print(f" {key} = {value}")
# Named groups for URL parsing
named_pattern = r"^(?P<protocol>https?)://(?P<domain>[^:/]+)(?::(?P<port>\d+))?(?P<path>/.*)?$"
named_p = re.compile(named_pattern)
match2 = named_p.match("https://example.com:8080/api/v1")
if match2:
print("\nNamed groups:")
print(f" Protocol: {match2.group('protocol')}")
print(f" Domain: {match2.group('domain')}")
print(f" Port: {match2.group('port')}")
print(f" Path: {match2.group('path')}")
url_pattern ← ^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}.*$, urls ← ['https://example.com', 'http://www.example.com', 'https://sub.example.co.uk', 'https://example.com/path', 'https://example.com/path?key=value', 'ftp://example.com', 'example.com', 'https://localhost']
6# Basic URL pattern7url_pattern→ ^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}.*$ = r"^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}.*$"89urls→ ['https://example.com', 'http://www.example.com', 'https://sub.example.co.uk', 'https://example.com/path', 'https://example.com/path?key=value', 'ftp://example.com', 'example.com', 'https://localhost'] = [10 "https://example.com",11 "http://www.example.com",12 "https://sub.example.co.uk",13 "https://example.com/path",14 "https://example.com/path?key=value",15 "ftp://example.com", # wrong protocol16 "example.com", # missing protocol17 "https://localhost" # no TLD18]1920print("URL validation:")21pattern→ re.compile('^https?://[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}.*$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(url_pattern^https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}.*$)22for url in urls:outputURL validation:valid ← True
pass 1 of 821pattern = re.compile(url_pattern)22for urlhttps://example.com in urls['https://example.com', 'http://www.example.com', 'https://sub.example.co.uk', 'https://example.com/path', 'https://example.com/path?key=value', 'ftp://example.com', 'example.com', 'https://localhost']:23 valid→ True = bool(patternre.compile('^https?://[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}.*$').match(urlhttps://example.com))24 print(f" {urlhttps://example.com}: {validTrue}")output https://example.com: TrueAll 8 passes — pass 1 is the card above pass urlvalid1 https://example.com True 2 http://www.example.com True 3 https://sub.example.co.uk True 4 https://example.com/path True 5 https://example.com/path?key=value True 6 ftp://example.com False 7 example.com False 8 https://localhost False extract_pattern ← ^(https?)://([a-zA-Z0-9.-]+)(/.*)? $, extract_p ← re.compile('^(https?)://([a-zA-Z0-9.-]+)(/.*)? $')
26# Extract URL parts27extract_pattern→ ^(https?)://([a-zA-Z0-9.-]+)(/.*)? $ = r"^(https?)://([a-zA-Z0-9.-]+)(/.*)? $"28extract_p→ re.compile('^(https?)://([a-zA-Z0-9.-]+)(/.*)? $') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(extract_pattern^(https?)://([a-zA-Z0-9.-]+)(/.*)? $)2930test_url→ https://www.example.com/path/to/page = "https://www.example.com/path/to/page"31match→ None = extract_pre.compile('^(https?)://([a-zA-Z0-9.-]+)(/.*)? $').match(test_urlhttps://www.example.com/path/to/page)3233if match:34 print(f"\nExtracted parts from {test_url}:")35 print(f" Protocol: {match.group(1)}")36 print(f" Domain: {match.group(2)}")37 print(f" Path: {match.group(3) if match.group(3) else '/'}")3839# More detailed extraction40detail_pattern→ ^(https?)://([^:/]+)(?::(\d+))?(/.*)?$ = r"^(https?)://([^:/]+)(?::(\d+))?(/.*)?$"41detail_p→ re.compile('^(https?)://([^:/]+)(?::(\\d+))?(/.*)?$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(detail_pattern^(https?)://([^:/]+)(?::(\d+))?(/.*)?$)4243test_urls→ ['https://example.com:8080/path', 'http://localhost:3000/api', 'https://example.com/page'] = [44 "https://example.com:8080/path",45 "http://localhost:3000/api",46 "https://example.com/page"47]4849print("\nDetailed URL parsing:")50for url in test_urls:output Detailed URL parsing:m ← <re.Match object; span=(0, 29), match='https://example.com:8080/path'>
pass 1 of 349print("\nDetailed URL parsing:")50for urlhttps://example.com:8080/path in test_urls['https://example.com:8080/path', 'http://localhost:3000/api', 'https://example.com/page']:51 m→ <re.Match object; span=(0, 29), match='https://example.com:8080/path'> = detail_pre.compile('^(https?)://([^:/]+)(?::(\\d+))?(/.*)?$').match(urlhttps://example.com:8080/path)52 if m:All 3 passes — pass 1 is the card above pass urlm1 https://example.com:8080/path <re.Match object; span=(0, 29), match='https://example.com:8080/path'> 2 http://localhost:3000/api <re.Match object; span=(0, 25), match='http://localhost:3000/api'> 3 https://example.com/page <re.Match object; span=(0, 24), match='https://example.com/page'> if m:
pass 1 of 351m = detail_p.match(url)52if m<re.Match object; span=(0, 29), match='https://example.com:8080/path'>:53 print(f" {urlhttps://example.com:8080/path}")54 print(f" Protocol: {m<re.Match object; span=(0, 29), match='https://example.com:8080/path'>.group(1)}")55 print(f" Host: {m<re.Match object; span=(0, 29), match='https://example.com:8080/path'>.group(2)}")56 print(f" Port: {m<re.Match object; span=(0, 29), match='https://example.com:8080/path'>.group(3) if m.group(3) else 'default'}")57 print(f" Path: {m<re.Match object; span=(0, 29), match='https://example.com:8080/path'>.group(4) if m.group(4) else '/'}")output https://example.com:8080/path Protocol: https Host: example.com Port: 8080 Path: /pathAll 3 passes — pass 1 is the card above pass murl1 <re.Match object; span=(0, 29), match='https://example.com:8080/path'> https://example.com:8080/path 2 <re.Match object; span=(0, 25), match='http://localhost:3000/api'> http://localhost:3000/api 3 <re.Match object; span=(0, 24), match='https://example.com/page'> https://example.com/page text ← Visit https://example.com for more info. Check out http://test.org/page and https://another.site/path?q=search
59# Find all URLs in text60text→ Visit https://example.com for more info. Check out http://test.org/page and https://another.site/path?q=search = """61Visit https://example.com for more info.62Check out http://test.org/page and https://another.site/path?q=search63"""6465find_pattern→ re.compile('https?://[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}[^\\s]*') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"https?://[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}[^\s]*")66found→ ['https://example.com', 'http://test.org/page', 'https://another.site/path?q=search'] = find_patternre.compile('https?://[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}[^\\s]*').findall(text Visit https://example.com for more info. Check out http://test.org/page and https://another.site/path?q=search )6768print("\nURLs found in text:")69for url in found:output URLs found in text:for url in found:
pass 1 of 368print("\nURLs found in text:")69for urlhttps://example.com in found['https://example.com', 'http://test.org/page', 'https://another.site/path?q=search']:70 print(f" {urlhttps://example.com}")output https://example.comAll 3 passes — pass 1 is the card above pass url1 https://example.com 2 http://test.org/page 3 https://another.site/path?q=search query_pattern ← [?&]([^=]+)=([^&]+), url_with_query ← https://example.com/search?q=regex&lang=python&page=1
72# Query parameters73query_pattern→ [?&]([^=]+)=([^&]+) = r"[?&]([^=]+)=([^&]+)"74url_with_query→ https://example.com/search?q=regex&lang=python&page=1 = "https://example.com/search?q=regex&lang=python&page=1"7576query_p→ re.compile('[?&]([^=]+)=([^&]+)') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(query_pattern[?&]([^=]+)=([^&]+))77params→ [('q', 'regex'), ('lang', 'python'), ('page', '1')] = query_pre.compile('[?&]([^=]+)=([^&]+)').findall(url_with_queryhttps://example.com/search?q=regex&lang=python&page=1)7879print(f"\nQuery parameters from: {url_with_queryhttps://example.com/search?q=regex&lang=python&page=1}")80for key, value in params:output Query parameters from: https://example.com/search?q=regex&lang=python&page=1for key, value in params:
pass 1 of 379print(f"\nQuery parameters from: {url_with_query}")80for keyq, valueregex in params[('q', 'regex'), ('lang', 'python'), ('page', '1')]:81 print(f" {keyq} = {valueregex}")output q = regexAll 3 passes — pass 1 is the card above pass keyvalue1 q regex 2 lang python 3 page 1 named_pattern ← ^(?P<protocol>https?)://(?P<domain>[^:/]+)(?::(?P<port>\d+))?(?P<path>/.*)?$
83# Named groups for URL parsing84named_pattern→ ^(?P<protocol>https?)://(?P<domain>[^:/]+)(?::(?P<port>\d+))?(?P<path>/.*)?$ = r"^(?P<protocol>https?)://(?P<domain>[^:/]+)(?::(?P<port>\d+))?(?P<path>/.*)?$"85named_p→ re.compile('^(?P<protocol>https?)://(?P<domain>[^:/]+)(?::(?P<port>\\d+))?(?P<path>/.*)?$') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(named_pattern^(?P<protocol>https?)://(?P<domain>[^:/]+)(?::(?P<port>\d+))?(?P<path>/.*)?$)8687match2→ <re.Match object; span=(0, 31), match='https://example.com:8080/api/v1'> = named_pre.compile('^(?P<protocol>https?)://(?P<domain>[^:/]+)(?::(?P<port>\\d+))?(?P<path>/.*)?$').match("https://example.com:8080/api/v1")88if match2:if match2:
87match2 = named_p.match("https://example.com:8080/api/v1")88if match2<re.Match object; span=(0, 31), match='https://example.com:8080/api/v1'>:89 print("\nNamed groups:")90 print(f" Protocol: {match2<re.Match object; span=(0, 31), match='https://example.com:8080/api/v1'>.group('protocol')}")91 print(f" Domain: {match2<re.Match object; span=(0, 31), match='https://example.com:8080/api/v1'>.group('domain')}")92 print(f" Port: {match2<re.Match object; span=(0, 31), match='https://example.com:8080/api/v1'>.group('port')}")93 print(f" Path: {match2<re.Match object; span=(0, 31), match='https://example.com:8080/api/v1'>.group('path')}")output Named groups: Protocol: https Domain: example.com Port: 8080 Path: /api/v1
url_pattern
Pattern for matching web URLs with http/https
Text Extraction
extraction.py
Replay: real traced execution (multi-file project)
# Text extraction with regex
import re
# Extract hashtags
def extract_hashtags(text):
"""Extract all hashtags from text"""
return re.findall(r"#\w+", text)
# Extract mentions
def extract_mentions(text):
"""Extract all @mentions from text"""
return re.findall(r"@\w+", text)
# Extract numbers
def extract_numbers(text):
"""Extract all numbers (including decimals and negatives)"""
matches = re.findall(r"-?\d+\.?\d*", text)
return [float(m) for m in matches if m and m != '-']
# Extract dates
def extract_dates(text):
"""Extract dates in YYYY-MM-DD format"""
return re.findall(r"\d{4}-\d{2}-\d{2}", text)
# Main test
if __name__ == "__main__":
# Social media text
tweet = """
Loving #python and #regex! Thanks @copilot for the help.
Check out #programming tips at https://example.com
Mentions: @user1 @user2 #coding
"""
print("Social media extraction:")
print(f"Hashtags: {extract_hashtags(tweet)}")
print(f"Mentions: {extract_mentions(tweet)}")
# Numbers
data_text = "Prices: $19.99, $5.50, and $100. Temperature: -5.5°C"
print("\nNumbers extraction:")
print(f"Numbers: {extract_numbers(data_text)}")
# Dates
log_text = """
2025-01-29: Error occurred
2025-01-30: Fixed bug
2025-02-01: Deployed
"""
print("\nDates extraction:")
print(f"Dates: {extract_dates(log_text)}")
# IP addresses
server_log = "Requests from 192.168.1.1, 10.0.0.5, and 172.16.0.10"
ips = re.findall(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", server_log)
print("\nIP addresses:")
for ip in ips:
print(f" {ip}")
# Extract quoted strings
quote_text = 'He said "Hello" and she replied "Hi there!"'
quotes = re.findall(r'"([^"]+)"', quote_text)
print("\nQuoted strings:")
for quote in quotes:
print(f" {quote}")
# Key-value pairs
config = "name=John age=30 city=NYC email=john@example.com"
kv_pairs = re.findall(r"(\w+)=(\S+)", config)
print("\nKey-value pairs:")
for key, value in kv_pairs:
print(f" {key} = {value}")
# HTML tags (simple)
html = "<div>Content</div><span>Text</span>"
# Using backreference \1 to match closing tag
tags = re.findall(r"<(\w+)>([^<]+)</\1>", html)
print("\nHTML content:")
for tag, content in tags:
print(f" <{tag}>: {content}")
# Email addresses
text_with_emails = "Contact alice@example.com or bob@test.org for info"
emails = re.findall(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", text_with_emails)
print("\nEmail addresses:")
for email in emails:
print(f" {email}")
# Extract words
sentence = "The quick-brown fox jumps over the lazy dog."
words = re.findall(r"\b\w+\b", sentence)
print(f"\nWords: {words}")
# Extract capitalized words
caps = re.findall(r"\b[A-Z]\w*\b", "Python, Java, and JavaScript are Languages")
print(f"Capitalized words: {caps}")
tweet ← Loving #python and #regex! Thanks @copilot for the help. Check out #programming tips at https://example.com Mentions: @user1 @user2 #coding
26# Main test27if __name__ == "__main__":28 # Social media text29 tweet→ Loving #python and #regex! Thanks @copilot for the help. Check out #programming tips at https://example.com Mentions: @user1 @user2 #coding = """30 Loving #python and #regex! Thanks @copilot for the help.31 Check out #programming tips at https://example.com32 Mentions: @user1 @user2 #coding33 """3435 print("Social media extraction:")36 print(f"Hashtags: {extract_hashtags(tweet Loving #python and #regex! Thanks @copilot for the help. Check out #programming tips at https://example.com Mentions: @user1 @user2 #coding )}")37 print(f"Mentions: {extract_mentions(tweet)}")outputSocial media extraction:def extract_hashtags(text):
5# Extract hashtags6def extract_hashtags(text Loving #python and #regex! Thanks @copilot for the help. Check out #programming tips at https://example.com Mentions: @user1 @user2 #coding ):7 """Extract all hashtags from text"""8 return re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"#\w+", text Loving #python and #regex! Thanks @copilot for the help. Check out #programming tips at https://example.com Mentions: @user1 @user2 #coding )print(f"Hashtags: {extract_hashtags(tweet)}")
35print("Social media extraction:")36print(f"Hashtags: {extract_hashtags(tweet Loving #python and #regex! Thanks @copilot for the help. Check out #programming tips at https://example.com Mentions: @user1 @user2 #coding )}")37print(f"Mentions: {extract_mentions(tweet Loving #python and #regex! Thanks @copilot for the help. Check out #programming tips at https://example.com Mentions: @user1 @user2 #coding )}")outputHashtags: ['#python', '#regex', '#programming', '#coding']def extract_mentions(text):
10# Extract mentions11def extract_mentions(text Loving #python and #regex! Thanks @copilot for the help. Check out #programming tips at https://example.com Mentions: @user1 @user2 #coding ):12 """Extract all @mentions from text"""13 return re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"@\w+", text Loving #python and #regex! Thanks @copilot for the help. Check out #programming tips at https://example.com Mentions: @user1 @user2 #coding )data_text ← Prices: $19.99, $5.50, and $100. Temperature: -5.5°C
36print(f"Hashtags: {extract_hashtags(tweet)}")37print(f"Mentions: {extract_mentions(tweet Loving #python and #regex! Thanks @copilot for the help. Check out #programming tips at https://example.com Mentions: @user1 @user2 #coding )}")3839# Numbers40data_text→ Prices: $19.99, $5.50, and $100. Temperature: -5.5°C = "Prices: $19.99, $5.50, and $100. Temperature: -5.5°C"41print("\nNumbers extraction:")42print(f"Numbers: {extract_numbers(data_textPrices: $19.99, $5.50, and $100. Temperature: -5.5°C)}")outputMentions: ['@copilot', '@user1', '@user2'] Numbers extraction:matches ← ['19.99', '5.50', '100.', '-5.5']
15# Extract numbers16def extract_numbers(textPrices: $19.99, $5.50, and $100. Temperature: -5.5°C):17 """Extract all numbers (including decimals and negatives)"""18 matches→ ['19.99', '5.50', '100.', '-5.5'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"-?\d+\.?\d*", textPrices: $19.99, $5.50, and $100. Temperature: -5.5°C)19 return [float(m) for m in matches['19.99', '5.50', '100.', '-5.5'] if m and m != '-']log_text ← 2025-01-29: Error occurred 2025-01-30: Fixed bug 2025-02-01: Deployed
41print("\nNumbers extraction:")42print(f"Numbers: {extract_numbers(data_textPrices: $19.99, $5.50, and $100. Temperature: -5.5°C)}")4344# Dates45log_text→ 2025-01-29: Error occurred 2025-01-30: Fixed bug 2025-02-01: Deployed = """462025-01-29: Error occurred472025-01-30: Fixed bug482025-02-01: Deployed49"""50print("\nDates extraction:")51print(f"Dates: {extract_dates(log_text 2025-01-29: Error occurred 2025-01-30: Fixed bug 2025-02-01: Deployed )}")outputNumbers: [19.99, 5.5, 100.0, -5.5] Dates extraction:def extract_dates(text):
21# Extract dates22def extract_dates(text 2025-01-29: Error occurred 2025-01-30: Fixed bug 2025-02-01: Deployed ):23 """Extract dates in YYYY-MM-DD format"""24 return re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"\d{4}-\d{2}-\d{2}", text 2025-01-29: Error occurred 2025-01-30: Fixed bug 2025-02-01: Deployed )server_log ← Requests from 192.168.1.1, 10.0.0.5, and 172.16.0.10
50print("\nDates extraction:")51print(f"Dates: {extract_dates(log_text 2025-01-29: Error occurred 2025-01-30: Fixed bug 2025-02-01: Deployed )}")5253# IP addresses54server_log→ Requests from 192.168.1.1, 10.0.0.5, and 172.16.0.10 = "Requests from 192.168.1.1, 10.0.0.5, and 172.16.0.10"55ips→ ['192.168.1.1', '10.0.0.5', '172.16.0.10'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", server_logRequests from 192.168.1.1, 10.0.0.5, and 172.16.0.10)56print("\nIP addresses:")57for ip in ips:outputDates: ['2025-01-29', '2025-01-30', '2025-02-01'] IP addresses:for ip in ips:
pass 1 of 356print("\nIP addresses:")57for ip192.168.1.1 in ips['192.168.1.1', '10.0.0.5', '172.16.0.10']:58 print(f" {ip192.168.1.1}")output 192.168.1.1All 3 passes — pass 1 is the card above pass ip1 192.168.1.1 2 10.0.0.5 3 172.16.0.10 quote_text ← He said "Hello" and she replied "Hi there!", quotes ← ['Hello', 'Hi there!']
60# Extract quoted strings61quote_text→ He said "Hello" and she replied "Hi there!" = 'He said "Hello" and she replied "Hi there!"'62quotes→ ['Hello', 'Hi there!'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r'"([^"]+)"', quote_textHe said "Hello" and she replied "Hi there!")63print("\nQuoted strings:")64for quote in quotes:output Quoted strings:for quote in quotes:
pass 1 of 263print("\nQuoted strings:")64for quoteHello in quotes['Hello', 'Hi there!']:65 print(f" {quoteHello}")output Hellofor quote in quotes:
pass 2 of 263print("\nQuoted strings:")64for quoteHi there! in quotes['Hello', 'Hi there!']:65 print(f" {quoteHi there!}")output Hi there!config ← name=John age=30 city=NYC email=john@example.com, kv_pairs ← [('name', 'John'), ('age', '30'), ('city', 'NYC'), ('email', 'john@example.com')]
67# Key-value pairs68config→ name=John age=30 city=NYC email=john@example.com = "name=John age=30 city=NYC email=john@example.com"69kv_pairs→ [('name', 'John'), ('age', '30'), ('city', 'NYC'), ('email', 'john@example.com')] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"(\w+)=(\S+)", configname=John age=30 city=NYC email=john@example.com)70print("\nKey-value pairs:")71for key, value in kv_pairs:output Key-value pairs:for key, value in kv_pairs:
pass 1 of 470print("\nKey-value pairs:")71for keyname, valueJohn in kv_pairs[('name', 'John'), ('age', '30'), ('city', 'NYC'), ('email', 'john@example.com')]:72 print(f" {keyname} = {valueJohn}")output name = JohnAll 4 passes — pass 1 is the card above pass keyvalue1 name John 2 age 30 3 city NYC 4 email john@example.com html ← <div>Content</div><span>Text</span>, tags ← [('div', 'Content'), ('span', 'Text')]
74# HTML tags (simple)75html→ <div>Content</div><span>Text</span> = "<div>Content</div><span>Text</span>"76# Using backreference \1 to match closing tag77tags→ [('div', 'Content'), ('span', 'Text')] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"<(\w+)>([^<]+)</\1>", html<div>Content</div><span>Text</span>)78print("\nHTML content:")79for tag, content in tags:output HTML content:for tag, content in tags:
pass 1 of 278print("\nHTML content:")79for tagdiv, contentContent in tags[('div', 'Content'), ('span', 'Text')]:80 print(f" <{tagdiv}>: {contentContent}")output <div>: Contentfor tag, content in tags:
pass 2 of 278print("\nHTML content:")79for tagspan, contentText in tags[('div', 'Content'), ('span', 'Text')]:80 print(f" <{tagspan}>: {contentText}")output <span>: Texttext_with_emails ← Contact alice@example.com or bob@test.org for info
82# Email addresses83text_with_emails→ Contact alice@example.com or bob@test.org for info = "Contact alice@example.com or bob@test.org for info"84emails→ ['alice@example.com', 'bob@test.org'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}", text_with_emailsContact alice@example.com or bob@test.org for info)85print("\nEmail addresses:")86for email in emails:output Email addresses:for email in emails:
pass 1 of 285print("\nEmail addresses:")86for emailalice@example.com in emails['alice@example.com', 'bob@test.org']:87 print(f" {emailalice@example.com}")output alice@example.comfor email in emails:
pass 2 of 285print("\nEmail addresses:")86for emailbob@test.org in emails['alice@example.com', 'bob@test.org']:87 print(f" {emailbob@test.org}")output bob@test.orgsentence ← The quick-brown fox jumps over the lazy dog., words ← ['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog']
89# Extract words90sentence→ The quick-brown fox jumps over the lazy dog. = "The quick-brown fox jumps over the lazy dog."91words→ ['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"\b\w+\b", sentenceThe quick-brown fox jumps over the lazy dog.)92print(f"\nWords: {words['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog']}")9394# Extract capitalized words95caps→ ['Python', 'Java', 'JavaScript', 'Languages'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"\b[A-Z]\w*\b", "Python, Java, and JavaScript are Languages")96print(f"Capitalized words: {caps['Python', 'Java', 'JavaScript', 'Languages']}")output Words: ['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog'] Capitalized words: ['Python', 'Java', 'JavaScript', 'Languages']
text_extraction
Extracting hashtags, mentions, numbers, and dates from text
Replacement Operations
replacement.py
Replay: real traced execution (multi-file project)
# String replacement with regex
import re
# Basic replacement
# Simple sub
text1 = "Hello World, Hello Python"
result1 = re.sub(r"Hello", "Hi", text1)
print(f"Original: {text1}")
print(f"Replaced: {result1}")
# Replace with pattern
text2 = "Call 555-1234 or 555-5678"
result2 = re.sub(r"\d{3}-\d{4}", "XXX-XXXX", text2)
print("\nMask phone numbers:")
print(f"Original: {text2}")
print(f"Masked: {result2}")
# Replace with groups
text3 = "2025-01-29"
result3 = re.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\2/\3/\1", text3)
print("\nReformat date:")
print(f"Original (YYYY-MM-DD): {text3}")
print(f"Reformatted (MM/DD/YYYY): {result3}")
# Remove extra whitespace
text4 = "Too many spaces"
result4 = re.sub(r"\s+", " ", text4)
print("\nNormalize whitespace:")
print(f"Original: '{text4}'")
print(f"Normalized: '{result4}'")
# Remove HTML tags
html = "<p>Hello <b>World</b></p>"
result5 = re.sub(r"<[^>]+>", "", html)
print("\nRemove HTML:")
print(f"Original: {html}")
print(f"Clean: {result5}")
# Censor profanity (example)
text6 = "This is bad and terrible"
result6 = re.sub(r"\b(bad|terrible)\b", "***", text6)
print("\nCensor words:")
print(f"Original: {text6}")
print(f"Censored: {result6}")
# Format currency
text7 = "Price: 1234.56"
result7 = re.sub(r"(\d+)", r"$\1", text7)
print("\nAdd currency:")
print(f"Original: {text7}")
print(f"Formatted: {result7}")
# Replacement with function
def uppercase_match(match):
"""Convert matched word to uppercase"""
return match.group(0).upper()
text8 = "one two three"
result8 = re.sub(r"\w+", uppercase_match, text8)
print("\nCustom replacement (function):")
print(f"Original: {text8}")
print(f"Uppercase: {result8}")
# Advanced: swap first and last name
names = "John Doe, Jane Smith, Bob Johnson"
result9 = re.sub(r"(\w+)\s(\w+)", r"\2, \1", names)
print("\nSwap names:")
print(f"Original: {names}")
print(f"Swapped: {result9}")
# Count replacements
text10 = "apple apple banana apple"
result10, count = re.subn(r"apple", "orange", text10)
print(f"\nReplace with count:")
print(f"Original: {text10}")
print(f"Replaced: {result10}")
print(f"Replacements: {count}")
# Replace only first N occurrences
text11 = "a a a a a"
result11 = re.sub(r"a", "b", text11, count=3)
print(f"\nReplace first 3:")
print(f"Original: {text11}")
print(f"Result: {result11}")
# Named groups in replacement
text12 = "John Doe"
pattern = r"(?P<first>\w+)\s(?P<last>\w+)"
result12 = re.sub(pattern, r"\g<last>, \g<first>", text12)
print(f"\nNamed group replacement:")
print(f"Original: {text12}")
print(f"Result: {result12}")
text1 ← Hello World, Hello Python, result1 ← Hi World, Hi Python
6# Simple sub7text1→ Hello World, Hello Python = "Hello World, Hello Python"8result1→ Hi World, Hi Python = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"Hello", "Hi", text1Hello World, Hello Python)9print(f"Original: {text1Hello World, Hello Python}")10print(f"Replaced: {result1Hi World, Hi Python}")1112# Replace with pattern13text2→ Call 555-1234 or 555-5678 = "Call 555-1234 or 555-5678"14result2→ Call XXX-XXXX or XXX-XXXX = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"\d{3}-\d{4}", "XXX-XXXX", text2Call 555-1234 or 555-5678)15print("\nMask phone numbers:")16print(f"Original: {text2Call 555-1234 or 555-5678}")17print(f"Masked: {result2Call XXX-XXXX or XXX-XXXX}")1819# Replace with groups20text3→ 2025-01-29 = "2025-01-29"21result3→ 01/29/2025 = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"(\d{4})-(\d{2})-(\d{2})", r"\2/\3/\1", text32025-01-29)22print("\nReformat date:")23print(f"Original (YYYY-MM-DD): {text32025-01-29}")24print(f"Reformatted (MM/DD/YYYY): {result301/29/2025}")2526# Remove extra whitespace27text4→ Too many spaces = "Too many spaces"28result4→ Too many spaces = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"\s+", " ", text4Too many spaces)29print("\nNormalize whitespace:")30print(f"Original: '{text4Too many spaces}'")31print(f"Normalized: '{result4Too many spaces}'")3233# Remove HTML tags34html→ <p>Hello <b>World</b></p> = "<p>Hello <b>World</b></p>"35result5→ Hello World = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"<[^>]+>", "", html<p>Hello <b>World</b></p>)36print("\nRemove HTML:")37print(f"Original: {html<p>Hello <b>World</b></p>}")38print(f"Clean: {result5Hello World}")3940# Censor profanity (example)41text6→ This is bad and terrible = "This is bad and terrible"42result6→ This is *** and *** = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"\b(bad|terrible)\b", "***", text6This is bad and terrible)43print("\nCensor words:")44print(f"Original: {text6This is bad and terrible}")45print(f"Censored: {result6This is *** and ***}")4647# Format currency48text7→ Price: 1234.56 = "Price: 1234.56"49result7→ Price: $1234.$56 = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"(\d+)", r"$\1", text7Price: 1234.56)50print("\nAdd currency:")51print(f"Original: {text7Price: 1234.56}")52print(f"Formatted: {result7Price: $1234.$56}")5354# Replacement with function55def uppercase_match(match):56 """Convert matched word to uppercase"""57 return match.group(0).upper()5859text8→ one two three = "one two three"60result8 = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"\w+", uppercase_match⟨function uppercase_match A⟩, text8one two three)61print("\nCustom replacement (function):")outputOriginal: Hello World, Hello Python Replaced: Hi World, Hi Python Mask phone numbers: Original: Call 555-1234 or 555-5678 Masked: Call XXX-XXXX or XXX-XXXX Reformat date: Original (YYYY-MM-DD): 2025-01-29 Reformatted (MM/DD/YYYY): 01/29/2025 Normalize whitespace: Original: 'Too many spaces' Normalized: 'Too many spaces' Remove HTML: Original: <p>Hello <b>World</b></p> Clean: Hello World Censor words: Original: This is bad and terrible Censored: This is *** and *** Add currency: Original: Price: 1234.56 Formatted: Price: $1234.$56def uppercase_match(match):
pass 1 of 354# Replacement with function55def uppercase_match(match<re.Match object; span=(0, 3), match='one'>):56 """Convert matched word to uppercase"""57 return match<re.Match object; span=(0, 3), match='one'>.group(0).upper()All 3 passes — pass 1 is the card above pass match1 <re.Match object; span=(0, 3), match='one'> 2 <re.Match object; span=(4, 7), match='two'> 3 <re.Match object; span=(8, 13), match='three'> result8 ← ONE TWO THREE, names ← John Doe, Jane Smith, Bob Johnson
59text8 = "one two three"60result8→ ONE TWO THREE = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"\w+", uppercase_match⟨function uppercase_match A⟩, text8one two three)61print("\nCustom replacement (function):")62print(f"Original: {text8one two three}")63print(f"Uppercase: {result8ONE TWO THREE}")6465# Advanced: swap first and last name66names→ John Doe, Jane Smith, Bob Johnson = "John Doe, Jane Smith, Bob Johnson"67result9→ Doe, John, Smith, Jane, Johnson, Bob = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"(\w+)\s(\w+)", r"\2, \1", namesJohn Doe, Jane Smith, Bob Johnson)68print("\nSwap names:")69print(f"Original: {namesJohn Doe, Jane Smith, Bob Johnson}")70print(f"Swapped: {result9Doe, John, Smith, Jane, Johnson, Bob}")7172# Count replacements73text10→ apple apple banana apple = "apple apple banana apple"74result10→ orange orange banana orange, count→ 3 = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.subn(r"apple", "orange", text10apple apple banana apple)75print(f"\nReplace with count:")76print(f"Original: {text10apple apple banana apple}")77print(f"Replaced: {result10orange orange banana orange}")78print(f"Replacements: {count3}")7980# Replace only first N occurrences81text11→ a a a a a = "a a a a a"82result11→ b b b a a = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(r"a", "b", text11a a a a a, count=3)83print(f"\nReplace first 3:")84print(f"Original: {text11a a a a a}")85print(f"Result: {result11b b b a a}")8687# Named groups in replacement88text12→ John Doe = "John Doe"89pattern→ (?P<first>\w+)\s(?P<last>\w+) = r"(?P<first>\w+)\s(?P<last>\w+)"90result12→ Doe, John = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.sub(pattern(?P<first>\w+)\s(?P<last>\w+), r"\g<last>, \g<first>", text12John Doe)91print(f"\nNamed group replacement:")92print(f"Original: {text12John Doe}")93print(f"Result: {result12Doe, John}")output Custom replacement (function): Original: one two three Uppercase: ONE TWO THREE Swap names: Original: John Doe, Jane Smith, Bob Johnson Swapped: Doe, John, Smith, Jane, Johnson, Bob Replace with count: Original: apple apple banana apple Replaced: orange orange banana orange Replacements: 3 Replace first 3: Original: a a a a a Result: b b b a a Named group replacement: Original: John Doe Result: Doe, John
regex_replacement
Using re.sub() to transform text with patterns
Splitting with Patterns
splitting.py
Replay: real traced execution (multi-file project)
# String splitting with regex
import re
# Basic splitting
# Split by comma
csv1 = "apple,banana,cherry"
parts1 = csv1.split(",")
print("Split by comma:")
print(f" {parts1}")
# Split by regex whitespace
text1 = "one two three four"
parts2 = re.split(r"\s+", text1)
print("\nSplit by whitespace:")
print(f" {parts2}")
# Split by multiple delimiters
text2 = "apple;banana,cherry:orange"
parts3 = re.split(r"[;,:]+", text2)
print("\nSplit by multiple delimiters:")
print(f" {parts3}")
# Split with limit (maxsplit)
text3 = "one,two,three,four,five"
parts4 = re.split(r",", text3, maxsplit=2)
print("\nSplit with maxsplit (2):")
print(f" {parts4}")
# Split preserving delimiters (use groups)
text4 = "one,two;three"
parts5 = re.split(r"([,;])", text4)
print("\nSplit preserving delimiters:")
print(f" {parts5}")
# Split by word boundaries
text5 = "hello-world_test"
parts6 = re.split(r"[-_]", text5)
print("\nSplit by hyphens and underscores:")
print(f" {parts6}")
# Split sentences
paragraph = "First sentence. Second sentence! Third question?"
sentences = re.split(r"[.!?]\s*", paragraph)
print("\nSplit sentences:")
for i, sent in enumerate(sentences, 1):
if sent: # skip empty strings
print(f" {i}: {sent}")
# Split keeping empty strings
text6 = "a,,b,,,c"
parts7 = text6.split(",") # regular split
parts8 = re.split(r",", text6) # regex split
print("\nRegular split:")
print(f" {parts7}")
print("Regex split (same behavior):")
print(f" {parts8}")
# Split path
path = r"C:\Users\John\Documents\file.txt"
path_parts = re.split(r"\\", path)
print("\nSplit Windows path:")
print(f" {path_parts}")
# Split by digits
text7 = "abc123def456ghi"
parts9 = re.split(r"\d+", text7)
print("\nSplit by digits:")
print(f" {parts9}")
# Compiled pattern for reuse
pattern = re.compile(r"\s*,\s*") # comma with optional spaces
text8 = "a, b,c ,d , e"
parts10 = pattern.split(text8)
print("\nSplit CSV with spaces:")
print(f" {parts10}")
# Split complex: key=value pairs
config = "name=John;age=30;city=NYC"
pairs = config.split(";")
print("\nParse config:")
for pair in pairs:
key, value = pair.split("=")
print(f" {key} -> {value}")
# Split with capturing groups
text9 = "a1b2c3"
parts11 = re.split(r"(\d)", text9)
print("\nSplit with captured delimiters:")
print(f" {parts11}")
# Split by lookahead (keep delimiter)
text10 = "HelloWorld"
parts12 = re.split(r"(?=[A-Z])", text10)
print("\nSplit before capitals:")
print(f" {parts12}")
# Split emails
emails = "alice@example.com, bob@test.org; charlie@demo.net"
email_list = re.split(r"[,;]\s*", emails)
print("\nSplit email list:")
for email in email_list:
print(f" {email}")
csv1 ← apple,banana,cherry, parts1 ← ['apple', 'banana', 'cherry']
6# Split by comma7csv1→ apple,banana,cherry = "apple,banana,cherry"8parts1→ ['apple', 'banana', 'cherry'] = csv1apple,banana,cherry.split(",")9print("Split by comma:")10print(f" {parts1['apple', 'banana', 'cherry']}")1112# Split by regex whitespace13text1→ one two three four = "one two three four"14parts2→ ['one', 'two', 'three', 'four'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r"\s+", text1one two three four)15print("\nSplit by whitespace:")16print(f" {parts2['one', 'two', 'three', 'four']}")1718# Split by multiple delimiters19text2→ apple;banana,cherry:orange = "apple;banana,cherry:orange"20parts3→ ['apple', 'banana', 'cherry', 'orange'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r"[;,:]+", text2apple;banana,cherry:orange)21print("\nSplit by multiple delimiters:")22print(f" {parts3['apple', 'banana', 'cherry', 'orange']}")2324# Split with limit (maxsplit)25text3→ one,two,three,four,five = "one,two,three,four,five"26parts4→ ['one', 'two', 'three,four,five'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r",", text3one,two,three,four,five, maxsplit=2)27print("\nSplit with maxsplit (2):")28print(f" {parts4['one', 'two', 'three,four,five']}")2930# Split preserving delimiters (use groups)31text4→ one,two;three = "one,two;three"32parts5→ ['one', ',', 'two', ';', 'three'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r"([,;])", text4one,two;three)33print("\nSplit preserving delimiters:")34print(f" {parts5['one', ',', 'two', ';', 'three']}")3536# Split by word boundaries37text5→ hello-world_test = "hello-world_test"38parts6→ ['hello', 'world', 'test'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r"[-_]", text5hello-world_test)39print("\nSplit by hyphens and underscores:")40print(f" {parts6['hello', 'world', 'test']}")4142# Split sentences43paragraph→ First sentence. Second sentence! Third question? = "First sentence. Second sentence! Third question?"44sentences→ ['First sentence', 'Second sentence', 'Third question', ''] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r"[.!?]\s*", paragraphFirst sentence. Second sentence! Third question?)45print("\nSplit sentences:")46for i, sent in enumerate(sentences, 1):outputSplit by comma: ['apple', 'banana', 'cherry'] Split by whitespace: ['one', 'two', 'three', 'four'] Split by multiple delimiters: ['apple', 'banana', 'cherry', 'orange'] Split with maxsplit (2): ['one', 'two', 'three,four,five'] Split preserving delimiters: ['one', ',', 'two', ';', 'three'] Split by hyphens and underscores: ['hello', 'world', 'test'] Split sentences:for i, sent in enumerate(sentences, 1):
pass 1 of 445print("\nSplit sentences:")46for i1, sentFirst sentence in enumerate(sentences['First sentence', 'Second sentence', 'Third question', ''], 1):47 if sent: # skip empty strings48 print(f" {i}: {sent}")All 4 passes — pass 1 is the card above pass isent1 1 First sentence 2 2 Second sentence 3 3 Third question 4 4 (empty) if sent: # skip empty strings
pass 1 of 346for i, sent in enumerate(sentences, 1):47 if sentFirst sentence: # skip empty strings48 print(f" {i1}: {sentFirst sentence}")output 1: First sentenceAll 3 passes — pass 1 is the card above pass senti1 First sentence 1 2 Second sentence 2 3 Third question 3 text6 ← a,,b,,,c, parts7 ← ['a', '', 'b', '', '', 'c'], parts8 ← ['a', '', 'b', '', '', 'c']
50# Split keeping empty strings51text6→ a,,b,,,c = "a,,b,,,c"52parts7→ ['a', '', 'b', '', '', 'c'] = text6a,,b,,,c.split(",") # regular split53parts8→ ['a', '', 'b', '', '', 'c'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r",", text6a,,b,,,c) # regex split54print("\nRegular split:")55print(f" {parts7['a', '', 'b', '', '', 'c']}")56print("Regex split (same behavior):")57print(f" {parts8['a', '', 'b', '', '', 'c']}")5859# Split path60path→ C:\Users\John\Documents\file.txt = r"C:\Users\John\Documents\file.txt"61path_parts→ ['C:', 'Users', 'John', 'Documents', 'file.txt'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r"\\", pathC:\Users\John\Documents\file.txt)62print("\nSplit Windows path:")63print(f" {path_parts['C:', 'Users', 'John', 'Documents', 'file.txt']}")6465# Split by digits66text7→ abc123def456ghi = "abc123def456ghi"67parts9→ ['abc', 'def', 'ghi'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r"\d+", text7abc123def456ghi)68print("\nSplit by digits:")69print(f" {parts9['abc', 'def', 'ghi']}")7071# Compiled pattern for reuse72pattern→ re.compile('\\s*,\\s*') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"\s*,\s*") # comma with optional spaces73text8→ a, b,c ,d , e = "a, b,c ,d , e"74parts10→ ['a', 'b', 'c', 'd', 'e'] = patternre.compile('\\s*,\\s*').split(text8a, b,c ,d , e)75print("\nSplit CSV with spaces:")76print(f" {parts10['a', 'b', 'c', 'd', 'e']}")7778# Split complex: key=value pairs79config→ name=John;age=30;city=NYC = "name=John;age=30;city=NYC"80pairs→ ['name=John', 'age=30', 'city=NYC'] = configname=John;age=30;city=NYC.split(";")81print("\nParse config:")82for pair in pairs:output Regular split: ['a', '', 'b', '', '', 'c'] Regex split (same behavior): ['a', '', 'b', '', '', 'c'] Split Windows path: ['C:', 'Users', 'John', 'Documents', 'file.txt'] Split by digits: ['abc', 'def', 'ghi'] Split CSV with spaces: ['a', 'b', 'c', 'd', 'e'] Parse config:key ← name, value ← John
pass 1 of 381print("\nParse config:")82for pairname=John in pairs['name=John', 'age=30', 'city=NYC']:83 key→ name, value→ John = pairname=John.split("=")84 print(f" {keyname} -> {valueJohn}")output name -> JohnAll 3 passes — pass 1 is the card above pass pairkeyvalue1 name=John name John 2 age=30 age 30 3 city=NYC city NYC text9 ← a1b2c3, parts11 ← ['a', '1', 'b', '2', 'c', '3', ''], text10 ← HelloWorld
86# Split with capturing groups87text9→ a1b2c3 = "a1b2c3"88parts11→ ['a', '1', 'b', '2', 'c', '3', ''] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r"(\d)", text9a1b2c3)89print("\nSplit with captured delimiters:")90print(f" {parts11['a', '1', 'b', '2', 'c', '3', '']}")9192# Split by lookahead (keep delimiter)93text10→ HelloWorld = "HelloWorld"94parts12→ ['', 'Hello', 'World'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r"(?=[A-Z])", text10HelloWorld)95print("\nSplit before capitals:")96print(f" {parts12['', 'Hello', 'World']}")9798# Split emails99emails→ alice@example.com, bob@test.org; charlie@demo.net = "alice@example.com, bob@test.org; charlie@demo.net"100email_list→ ['alice@example.com', 'bob@test.org', 'charlie@demo.net'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.split(r"[,;]\s*", emailsalice@example.com, bob@test.org; charlie@demo.net)101print("\nSplit email list:")102for email in email_list:output Split with captured delimiters: ['a', '1', 'b', '2', 'c', '3', ''] Split before capitals: ['', 'Hello', 'World'] Split email list:for email in email_list:
pass 1 of 3101print("\nSplit email list:")102for emailalice@example.com in email_list['alice@example.com', 'bob@test.org', 'charlie@demo.net']:103 print(f" {emailalice@example.com}")output alice@example.comAll 3 passes — pass 1 is the card above pass email1 alice@example.com 2 bob@test.org 3 charlie@demo.net
regex_splitting
Using re.split() to divide text on complex delimiters
Pattern Building Tips
- Start simple, add complexity
- Test with edge cases
- Use raw strings (r"...")
- Use groups for extraction
- Balance strictness vs flexibility
Exercise: extraction.py
Extract all emails, URLs, and hashtags from a sample social media post