String Processing
Regular Expressions Introduction
Validating email addresses, parsing log files, and extracting data from text are tedious with basic string methods. Regular expressions provide a powerful pattern language for matching, searching, and manipulating text. Python's re module makes these patterns accessible for validation, extraction, and text transformation.
Regular expressions (regex) are patterns used to match character combinations in strings. They provide a powerful way to search, validate, and manipulate text.
Literal Matching
literal.py
Replay: real traced execution (multi-file project)
# Literal matching
import re
# Basic pattern matching
# Literal match
text1 = "hello"
match1 = re.match(r"hello", text1)
print(f"'hello' matches 'hello': {match1 is not None}")
match2 = re.match(r"world", text1)
print(f"'hello' matches 'world': {match2 is not None}")
# Full match vs partial match
print("\nFull match vs search:")
print(f"Full match 'hello' in 'hello world': {re.fullmatch(r'hello', 'hello world') is not None}")
print(f"Search 'hello' in 'hello world': {re.search(r'hello', 'hello world') is not None}")
# Compiled pattern
pattern = re.compile(r"hello")
match3 = pattern.search("hello world")
print(f"\nCompiled pattern found: {match3 is not None}")
# Case sensitivity
match4 = re.match(r"hello", "Hello")
print(f"\n'Hello' matches 'hello': {match4 is not None}")
# Case insensitive
match5 = re.match(r"hello", "Hello", re.IGNORECASE)
print(f"Case insensitive match: {match5 is not None}")
# Multiple occurrences
text2 = "hello hello hello"
matches = re.finditer(r"hello", text2)
print("\nFind all occurrences:")
for match in matches:
print(f" Found at index: {match.start()}")
# Match object details
text3 = "hello world"
match6 = re.search(r"hello", text3)
if match6:
print(f"\nMatch details:")
print(f" Matched text: {match6.group()}")
print(f" Start: {match6.start()}, End: {match6.end()}")
print(f" Span: {match6.span()}")
# Literal matching
import re
# Basic pattern matching
# Literal match
text1 = "Hello"
match1 = re.match(r"hello", text1)
print(f"'hello' matches 'hello': {match1 is not None}")
match2 = re.match(r"world", text1)
print(f"'hello' matches 'world': {match2 is not None}")
# Full match vs partial match
print("\nFull match vs search:")
print(f"Full match 'hello' in 'hello world': {re.fullmatch(r'hello', 'hello world') is not None}")
print(f"Search 'hello' in 'hello world': {re.search(r'hello', 'hello world') is not None}")
# Compiled pattern
pattern = re.compile(r"hello")
match3 = pattern.search("hello world")
print(f"\nCompiled pattern found: {match3 is not None}")
# Case sensitivity
match4 = re.match(r"hello", "Hello")
print(f"\n'Hello' matches 'hello': {match4 is not None}")
# Case insensitive
match5 = re.match(r"hello", "Hello", re.IGNORECASE)
print(f"Case insensitive match: {match5 is not None}")
# Multiple occurrences
text2 = "hello hello hello"
matches = re.finditer(r"hello", text2)
print("\nFind all occurrences:")
for match in matches:
print(f" Found at index: {match.start()}")
# Match object details
text3 = "hello world"
match6 = re.search(r"hello", text3)
if match6:
print(f"\nMatch details:")
print(f" Matched text: {match6.group()}")
print(f" Start: {match6.start()}, End: {match6.end()}")
print(f" Span: {match6.span()}")
# Literal matching
import re
# Basic pattern matching
# Literal match
text1 = "world"
match1 = re.match(r"hello", text1)
print(f"'hello' matches 'hello': {match1 is not None}")
match2 = re.match(r"world", text1)
print(f"'hello' matches 'world': {match2 is not None}")
# Full match vs partial match
print("\nFull match vs search:")
print(f"Full match 'hello' in 'hello world': {re.fullmatch(r'hello', 'hello world') is not None}")
print(f"Search 'hello' in 'hello world': {re.search(r'hello', 'hello world') is not None}")
# Compiled pattern
pattern = re.compile(r"hello")
match3 = pattern.search("hello world")
print(f"\nCompiled pattern found: {match3 is not None}")
# Case sensitivity
match4 = re.match(r"hello", "Hello")
print(f"\n'Hello' matches 'hello': {match4 is not None}")
# Case insensitive
match5 = re.match(r"hello", "Hello", re.IGNORECASE)
print(f"Case insensitive match: {match5 is not None}")
# Multiple occurrences
text2 = "hello hello hello"
matches = re.finditer(r"hello", text2)
print("\nFind all occurrences:")
for match in matches:
print(f" Found at index: {match.start()}")
# Match object details
text3 = "hello world"
match6 = re.search(r"hello", text3)
if match6:
print(f"\nMatch details:")
print(f" Matched text: {match6.group()}")
print(f" Start: {match6.start()}, End: {match6.end()}")
print(f" Span: {match6.span()}")
text1 ← hello, match1 ← <re.Match object; span=(0, 5), match='hello'>
6# Literal match7text1→ hello = "hello"8#@text1="Hello", "world"9match1→ <re.Match object; span=(0, 5), match='hello'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"hello", text1hello)10print(f"'hello' matches 'hello': {match1<re.Match object; span=(0, 5), match='hello'> is not None}")1112match2→ None = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"world", text1hello)13print(f"'hello' matches 'world': {match2None is not None}")1415# Full match vs partial match16print("\nFull match vs search:")17print(f"Full match 'hello' in 'hello world': {re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r'hello', 'hello world') is not None}")18print(f"Search 'hello' in 'hello world': {re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r'hello', 'hello world') is not None}")1920# Compiled pattern21pattern→ re.compile('hello') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"hello")22match3→ <re.Match object; span=(0, 5), match='hello'> = patternre.compile('hello').search("hello world")23print(f"\nCompiled pattern found: {match3<re.Match object; span=(0, 5), match='hello'> is not None}")2425# Case sensitivity26match4→ None = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"hello", "Hello")27print(f"\n'Hello' matches 'hello': {match4None is not None}")2829# Case insensitive30match5→ <re.Match object; span=(0, 5), match='Hello'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"hello", "Hello", re.IGNORECASEre.IGNORECASE)31print(f"Case insensitive match: {match5<re.Match object; span=(0, 5), match='Hello'> is not None}")3233# Multiple occurrences34text2→ hello hello hello = "hello hello hello"35matches→ ⟨callable_iterator A⟩ = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.finditer(r"hello", text2hello hello hello)3637print("\nFind all occurrences:")38for match in matches:output'hello' matches 'hello': True 'hello' matches 'world': False Full match vs search: Full match 'hello' in 'hello world': False Search 'hello' in 'hello world': True Compiled pattern found: True 'Hello' matches 'hello': False Case insensitive match: True Find all occurrences:for match in matches:
pass 1 of 337print("\nFind all occurrences:")38for match<re.Match object; span=(0, 5), match='hello'> in matches⟨callable_iterator A⟩:39 print(f" Found at index: {match<re.Match object; span=(0, 5), match='hello'>.start()}")output Found at index: 0All 3 passes — pass 1 is the card above pass match1 <re.Match object; span=(0, 5), match='hello'> 2 <re.Match object; span=(6, 11), match='hello'> 3 <re.Match object; span=(12, 17), match='hello'> text3 ← hello world, match6 ← <re.Match object; span=(0, 5), match='hello'>
41# Match object details42text3→ hello world = "hello world"43match6→ <re.Match object; span=(0, 5), match='hello'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"hello", text3hello world)44if match6:if match6:
43match6 = re.search(r"hello", text3)44if match6<re.Match object; span=(0, 5), match='hello'>:45 print(f"\nMatch details:")46 print(f" Matched text: {match6<re.Match object; span=(0, 5), match='hello'>.group()}")47 print(f" Start: {match6<re.Match object; span=(0, 5), match='hello'>.start()}, End: {match6.end()}")48 print(f" Span: {match6<re.Match object; span=(0, 5), match='hello'>.span()}")output Match details: Matched text: hello Start: 0, End: 5 Span: (0, 5)
text1 ← Hello, match1 ← None, match2 ← None, pattern ← re.compile('hello')
6# Literal match7text1→ Hello = "Hello"8match1→ None = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"hello", text1Hello)9print(f"'hello' matches 'hello': {match1None is not None}")1011match2→ None = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"world", text1Hello)12print(f"'hello' matches 'world': {match2None is not None}")1314# Full match vs partial match15print("\nFull match vs search:")16print(f"Full match 'hello' in 'hello world': {re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r'hello', 'hello world') is not None}")17print(f"Search 'hello' in 'hello world': {re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r'hello', 'hello world') is not None}")1819# Compiled pattern20pattern→ re.compile('hello') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"hello")21match3→ <re.Match object; span=(0, 5), match='hello'> = patternre.compile('hello').search("hello world")22print(f"\nCompiled pattern found: {match3<re.Match object; span=(0, 5), match='hello'> is not None}")2324# Case sensitivity25match4→ None = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"hello", "Hello")26print(f"\n'Hello' matches 'hello': {match4None is not None}")2728# Case insensitive29match5→ <re.Match object; span=(0, 5), match='Hello'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"hello", "Hello", re.IGNORECASEre.IGNORECASE)30print(f"Case insensitive match: {match5<re.Match object; span=(0, 5), match='Hello'> is not None}")3132# Multiple occurrences33text2→ hello hello hello = "hello hello hello"34matches→ ⟨callable_iterator A⟩ = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.finditer(r"hello", text2hello hello hello)3536print("\nFind all occurrences:")37for match in matches:output'hello' matches 'hello': False 'hello' matches 'world': False Full match vs search: Full match 'hello' in 'hello world': False Search 'hello' in 'hello world': True Compiled pattern found: True 'Hello' matches 'hello': False Case insensitive match: True Find all occurrences:for match in matches:
pass 1 of 336print("\nFind all occurrences:")37for match<re.Match object; span=(0, 5), match='hello'> in matches⟨callable_iterator A⟩:38 print(f" Found at index: {match<re.Match object; span=(0, 5), match='hello'>.start()}")output Found at index: 0All 3 passes — pass 1 is the card above pass match1 <re.Match object; span=(0, 5), match='hello'> 2 <re.Match object; span=(6, 11), match='hello'> 3 <re.Match object; span=(12, 17), match='hello'> text3 ← hello world, match6 ← <re.Match object; span=(0, 5), match='hello'>
40# Match object details41text3→ hello world = "hello world"42match6→ <re.Match object; span=(0, 5), match='hello'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"hello", text3hello world)43if match6:if match6:
42match6 = re.search(r"hello", text3)43if match6<re.Match object; span=(0, 5), match='hello'>:44 print(f"\nMatch details:")45 print(f" Matched text: {match6<re.Match object; span=(0, 5), match='hello'>.group()}")46 print(f" Start: {match6<re.Match object; span=(0, 5), match='hello'>.start()}, End: {match6.end()}")47 print(f" Span: {match6<re.Match object; span=(0, 5), match='hello'>.span()}")output Match details: Matched text: hello Start: 0, End: 5 Span: (0, 5)
text1 ← world, match1 ← None, match2 ← <re.Match object; span=(0, 5), match='world'>
6# Literal match7text1→ world = "world"8match1→ None = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"hello", text1world)9print(f"'hello' matches 'hello': {match1None is not None}")1011match2→ <re.Match object; span=(0, 5), match='world'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"world", text1world)12print(f"'hello' matches 'world': {match2<re.Match object; span=(0, 5), match='world'> is not None}")1314# Full match vs partial match15print("\nFull match vs search:")16print(f"Full match 'hello' in 'hello world': {re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r'hello', 'hello world') is not None}")17print(f"Search 'hello' in 'hello world': {re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r'hello', 'hello world') is not None}")1819# Compiled pattern20pattern→ re.compile('hello') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"hello")21match3→ <re.Match object; span=(0, 5), match='hello'> = patternre.compile('hello').search("hello world")22print(f"\nCompiled pattern found: {match3<re.Match object; span=(0, 5), match='hello'> is not None}")2324# Case sensitivity25match4→ None = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"hello", "Hello")26print(f"\n'Hello' matches 'hello': {match4None is not None}")2728# Case insensitive29match5→ <re.Match object; span=(0, 5), match='Hello'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"hello", "Hello", re.IGNORECASEre.IGNORECASE)30print(f"Case insensitive match: {match5<re.Match object; span=(0, 5), match='Hello'> is not None}")3132# Multiple occurrences33text2→ hello hello hello = "hello hello hello"34matches→ ⟨callable_iterator A⟩ = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.finditer(r"hello", text2hello hello hello)3536print("\nFind all occurrences:")37for match in matches:output'hello' matches 'hello': False 'hello' matches 'world': True Full match vs search: Full match 'hello' in 'hello world': False Search 'hello' in 'hello world': True Compiled pattern found: True 'Hello' matches 'hello': False Case insensitive match: True Find all occurrences:for match in matches:
pass 1 of 336print("\nFind all occurrences:")37for match<re.Match object; span=(0, 5), match='hello'> in matches⟨callable_iterator A⟩:38 print(f" Found at index: {match<re.Match object; span=(0, 5), match='hello'>.start()}")output Found at index: 0All 3 passes — pass 1 is the card above pass match1 <re.Match object; span=(0, 5), match='hello'> 2 <re.Match object; span=(6, 11), match='hello'> 3 <re.Match object; span=(12, 17), match='hello'> text3 ← hello world, match6 ← <re.Match object; span=(0, 5), match='hello'>
40# Match object details41text3→ hello world = "hello world"42match6→ <re.Match object; span=(0, 5), match='hello'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"hello", text3hello world)43if match6:if match6:
42match6 = re.search(r"hello", text3)43if match6<re.Match object; span=(0, 5), match='hello'>:44 print(f"\nMatch details:")45 print(f" Matched text: {match6<re.Match object; span=(0, 5), match='hello'>.group()}")46 print(f" Start: {match6<re.Match object; span=(0, 5), match='hello'>.start()}, End: {match6.end()}")47 print(f" Span: {match6<re.Match object; span=(0, 5), match='hello'>.span()}")output Match details: Matched text: hello Start: 0, End: 5 Span: (0, 5)
literal_match
Basic exact text matching with re.match(), re.search(), and re.fullmatch()
Character Classes
character_class.py
Replay: real traced execution (multi-file project)
# Character classes
import re
# Character class [abc]
# Match one of specific characters
print("a" == re.fullmatch(r"[abc]", "a").group() if re.fullmatch(r"[abc]", "a") else False)
print("b" == re.fullmatch(r"[abc]", "b").group() if re.fullmatch(r"[abc]", "b") else False)
print("d matches [abc]:", re.fullmatch(r"[abc]", "d") is not None)
# Range
print("\nRanges:")
print("5 matches [0-9]:", re.fullmatch(r"[0-9]", "5") is not None)
print("m matches [a-z]:", re.fullmatch(r"[a-z]", "m") is not None)
print("M matches [A-Z]:", re.fullmatch(r"[A-Z]", "M") is not None)
print("M matches [a-z]:", re.fullmatch(r"[a-z]", "M") is not None)
# Multiple ranges
print("\nMultiple ranges:")
print("a matches [a-zA-Z]:", re.fullmatch(r"[a-zA-Z]", "a") is not None)
print("5 matches [a-zA-Z]:", re.fullmatch(r"[a-zA-Z]", "5") is not None)
print("5 matches [a-zA-Z0-9]:", re.fullmatch(r"[a-zA-Z0-9]", "5") is not None)
# Negation [^...]
print("\nNegation:")
print("a matches [^0-9]:", re.fullmatch(r"[^0-9]", "a") is not None)
print("5 matches [^0-9]:", re.fullmatch(r"[^0-9]", "5") is not None)
# Predefined character classes
print("\nPredefined classes:")
print(r"5 matches \d:", re.fullmatch(r"\d", "5") is not None)
print(r"a matches \d:", re.fullmatch(r"\d", "a") is not None)
print(r"a matches \w:", re.fullmatch(r"\w", "a") is not None)
print(r"space matches \s:", re.fullmatch(r"\s", " ") is not None)
print(r"a matches \D:", re.fullmatch(r"\D", "a") is not None)
print(r"5 matches \D:", re.fullmatch(r"\D", "5") is not None)
# Dot . matches any character
print("\nDot (any char):")
print("a matches .:", re.fullmatch(r".", "a") is not None)
print("5 matches .:", re.fullmatch(r".", "5") is not None)
print("space matches .:", re.fullmatch(r".", " ") is not None)
# Escape special chars
print("\nEscape special chars:")
print(r"\.:", re.search(r"\.", "hello.world") is not None)
print(r"literal dot at:", re.search(r"\.", "hello.world").start())
print("a" == re.fullmatch(r"[abc]", "a").group() if re.fullmatch(r"[ab…
6# Match one of specific characters7print("a" == re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[abc]", "a").group() if re.fullmatch(r"[abc]", "a") else False)8print("b" == re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[abc]", "b").group() if re.fullmatch(r"[abc]", "b") else False)9print("d matches [abc]:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[abc]", "d") is not None)1011# Range12print("\nRanges:")13print("5 matches [0-9]:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[0-9]", "5") is not None)14print("m matches [a-z]:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[a-z]", "m") is not None)15print("M matches [A-Z]:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[A-Z]", "M") is not None)16print("M matches [a-z]:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[a-z]", "M") is not None)1718# Multiple ranges19print("\nMultiple ranges:")20print("a matches [a-zA-Z]:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[a-zA-Z]", "a") is not None)21print("5 matches [a-zA-Z]:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[a-zA-Z]", "5") is not None)22print("5 matches [a-zA-Z0-9]:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[a-zA-Z0-9]", "5") is not None)2324# Negation [^...]25print("\nNegation:")26print("a matches [^0-9]:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[^0-9]", "a") is not None)27print("5 matches [^0-9]:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"[^0-9]", "5") is not None)2829# Predefined character classes30print("\nPredefined classes:")31print(r"5 matches \d:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"\d", "5") is not None)32print(r"a matches \d:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"\d", "a") is not None)33print(r"a matches \w:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"\w", "a") is not None)34print(r"space matches \s:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"\s", " ") is not None)35print(r"a matches \D:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"\D", "a") is not None)36print(r"5 matches \D:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"\D", "5") is not None)3738# Dot . matches any character39print("\nDot (any char):")40print("a matches .:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r".", "a") is not None)41print("5 matches .:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r".", "5") is not None)42print("space matches .:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r".", " ") is not None)4344# Escape special chars45print("\nEscape special chars:")46print(r"\.:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"\.", "hello.world") is not None)47print(r"literal dot at:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"\.", "hello.world").start())outputd matches [abc]: False Ranges: 5 matches [0-9]: True m matches [a-z]: True M matches [A-Z]: True M matches [a-z]: False Multiple ranges: a matches [a-zA-Z]: True 5 matches [a-zA-Z]: False 5 matches [a-zA-Z0-9]: True Negation: a matches [^0-9]: True 5 matches [^0-9]: False Predefined classes: 5 matches \d: True a matches \d: False a matches \w: True space matches \s: True a matches \D: True 5 matches \D: False Dot (any char): a matches .: True 5 matches .: True space matches .: True Escape special chars: \.: True literal dot at: 5
character_class
Matching sets of characters with [abc], [a-z], and predefined classes like \\d and \\w
Quantifiers
quantifiers.py
Replay: real traced execution (multi-file project)
# Quantifiers
import re
# Quantifiers
# * (0 or more)
print("Asterisk * (0 or more):")
print("'' matches a*:", re.fullmatch(r"a*", "") is not None)
print("'a' matches a*:", re.fullmatch(r"a*", "a") is not None)
print("'aaa' matches a*:", re.fullmatch(r"a*", "aaa") is not None)
print("'b' matches a*:", re.fullmatch(r"a*", "b") is not None)
# + (1 or more)
print("\nPlus + (1 or more):")
print("'' matches a+:", re.fullmatch(r"a+", "") is not None)
print("'a' matches a+:", re.fullmatch(r"a+", "a") is not None)
print("'aaa' matches a+:", re.fullmatch(r"a+", "aaa") is not None)
# ? (0 or 1)
print("\nQuestion ? (0 or 1):")
print("'' matches a?:", re.fullmatch(r"a?", "") is not None)
print("'a' matches a?:", re.fullmatch(r"a?", "a") is not None)
print("'aa' matches a?:", re.fullmatch(r"a?", "aa") is not None)
# {n} (exactly n)
print("\n{n} (exactly n):")
print("'aa' matches a{2}:", re.fullmatch(r"a{2}", "aa") is not None)
print("'aaa' matches a{2}:", re.fullmatch(r"a{2}", "aaa") is not None)
print("'a' matches a{2}:", re.fullmatch(r"a{2}", "a") is not None)
# {n,} (n or more)
print("\n{n,} (n or more):")
print("'aa' matches a{2,}:", re.fullmatch(r"a{2,}", "aa") is not None)
print("'aaa' matches a{2,}:", re.fullmatch(r"a{2,}", "aaa") is not None)
print("'a' matches a{2,}:", re.fullmatch(r"a{2,}", "a") is not None)
# {n,m} (between n and m)
print("\n{n,m} (between n and m):")
print("'aa' matches a{2,4}:", re.fullmatch(r"a{2,4}", "aa") is not None)
print("'aaa' matches a{2,4}:", re.fullmatch(r"a{2,4}", "aaa") is not None)
print("'aaaa' matches a{2,4}:", re.fullmatch(r"a{2,4}", "aaaa") is not None)
print("'a' matches a{2,4}:", re.fullmatch(r"a{2,4}", "a") is not None)
print("'aaaaa' matches a{2,4}:", re.fullmatch(r"a{2,4}", "aaaaa") is not None)
# Practical: digits
print("\nPractical - validate numbers:")
print(r"'123' matches \d+:", re.fullmatch(r"\d+", "123") is not None)
print(r"'12345' matches \d{5}:", re.fullmatch(r"\d{5}", "12345") is not None)
print(r"'123' matches \d{2,4}:", re.fullmatch(r"\d{2,4}", "123") is not None)
# Greedy vs non-greedy
print("\nGreedy vs non-greedy:")
text = "<tag>content</tag>"
greedy = re.search(r"<.*>", text)
non_greedy = re.search(r"<.*?>", text)
print(f"Greedy: {greedy.group()}")
print(f"Non-greedy: {non_greedy.group()}")
text ← <tag>content</tag>, greedy ← <re.Match object; span=(0, 18), match='<tag>content</tag>'>
6# * (0 or more)7print("Asterisk * (0 or more):")8print("'' matches a*:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a*", "") is not None)9print("'a' matches a*:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a*", "a") is not None)10print("'aaa' matches a*:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a*", "aaa") is not None)11print("'b' matches a*:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a*", "b") is not None)1213# + (1 or more)14print("\nPlus + (1 or more):")15print("'' matches a+:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a+", "") is not None)16print("'a' matches a+:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a+", "a") is not None)17print("'aaa' matches a+:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a+", "aaa") is not None)1819# ? (0 or 1)20print("\nQuestion ? (0 or 1):")21print("'' matches a?:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a?", "") is not None)22print("'a' matches a?:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a?", "a") is not None)23print("'aa' matches a?:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a?", "aa") is not None)2425# {n} (exactly n)26print("\n{n} (exactly n):")27print("'aa' matches a{2}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2}", "aa") is not None)28print("'aaa' matches a{2}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2}", "aaa") is not None)29print("'a' matches a{2}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2}", "a") is not None)3031# {n,} (n or more)32print("\n{n,} (n or more):")33print("'aa' matches a{2,}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2,}", "aa") is not None)34print("'aaa' matches a{2,}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2,}", "aaa") is not None)35print("'a' matches a{2,}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2,}", "a") is not None)3637# {n,m} (between n and m)38print("\n{n,m} (between n and m):")39print("'aa' matches a{2,4}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2,4}", "aa") is not None)40print("'aaa' matches a{2,4}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2,4}", "aaa") is not None)41print("'aaaa' matches a{2,4}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2,4}", "aaaa") is not None)42print("'a' matches a{2,4}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2,4}", "a") is not None)43print("'aaaaa' matches a{2,4}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"a{2,4}", "aaaaa") is not None)4445# Practical: digits46print("\nPractical - validate numbers:")47print(r"'123' matches \d+:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"\d+", "123") is not None)48print(r"'12345' matches \d{5}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"\d{5}", "12345") is not None)49print(r"'123' matches \d{2,4}:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"\d{2,4}", "123") is not None)5051# Greedy vs non-greedy52print("\nGreedy vs non-greedy:")53text→ <tag>content</tag> = "<tag>content</tag>"54greedy→ <re.Match object; span=(0, 18), match='<tag>content</tag>'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"<.*>", text<tag>content</tag>)55non_greedy→ <re.Match object; span=(0, 5), match='<tag>'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"<.*?>", text<tag>content</tag>)56print(f"Greedy: {greedy<re.Match object; span=(0, 18), match='<tag>content</tag>'>.group()}")57print(f"Non-greedy: {non_greedy<re.Match object; span=(0, 5), match='<tag>'>.group()}")outputAsterisk * (0 or more): '' matches a*: True 'a' matches a*: True 'aaa' matches a*: True 'b' matches a*: False Plus + (1 or more): '' matches a+: False 'a' matches a+: True 'aaa' matches a+: True Question ? (0 or 1): '' matches a?: True 'a' matches a?: True 'aa' matches a?: False {n} (exactly n): 'aa' matches a{2}: True 'aaa' matches a{2}: False 'a' matches a{2}: False {n,} (n or more): 'aa' matches a{2,}: True 'aaa' matches a{2,}: True 'a' matches a{2,}: False {n,m} (between n and m): 'aa' matches a{2,4}: True 'aaa' matches a{2,4}: True 'aaaa' matches a{2,4}: True 'a' matches a{2,4}: False 'aaaaa' matches a{2,4}: False Practical - validate numbers: '123' matches \d+: True '12345' matches \d{5}: True '123' matches \d{2,4}: True Greedy vs non-greedy: Greedy: <tag>content</tag> Non-greedy: <tag>
quantifiers
Specifying repetition with *, +, ?, and {n,m}
Anchors
anchors.py
Replay: real traced execution (multi-file project)
# Anchors
import re
# Anchors ^ and $
# ^ (start of string)
print("Start anchor ^:")
print("'hello' matches ^hello:", re.match(r"^hello", "hello") is not None)
print("'hello world' matches ^hello:", re.match(r"^hello", "hello world") is not None)
print("'world hello' matches ^hello:", re.match(r"^hello", "world hello") is not None)
# $ (end of string)
print("\nEnd anchor $:")
print("'hello' matches hello$:", re.search(r"hello$", "hello") is not None)
print("'hello world' matches world$:", re.search(r"world$", "hello world") is not None)
print("'world hello' matches world$:", re.search(r"world$", "world hello") is not None)
# Both anchors
print("\nBoth anchors ^...$:")
print("'hello' matches ^hello$:", re.fullmatch(r"^hello$", "hello") is not None)
print("'hello world' matches ^hello$:", re.fullmatch(r"^hello$", "hello world") is not None)
# \b (word boundary)
print(r"\nWord boundary \b:")
text = "hello world"
print(f"Text: '{text}'")
print(r"\bhello\b found:", re.search(r"\bhello\b", text) is not None)
print(r"\bworld\b found:", re.search(r"\bworld\b", text) is not None)
print(r"\bhello\b in 'helloworld':", re.search(r"\bhello\b", "helloworld") is not None)
# Practical examples
print("\nPractical validation:")
# Must start with letter
print("'abc123' starts with letter:", re.match(r"^[a-zA-Z]", "abc123") is not None)
print("'123abc' starts with letter:", re.match(r"^[a-zA-Z]", "123abc") is not None)
# Must end with digit
print(r"'abc123' ends with digit:", re.search(r"\d$", "abc123") is not None)
print(r"'abc' ends with digit:", re.search(r"\d$", "abc") is not None)
# Exact length
print(r"'12345' is exactly 5 digits:", re.fullmatch(r"^\d{5}$", "12345") is not None)
print(r"'1234' is exactly 5 digits:", re.fullmatch(r"^\d{5}$", "1234") is not None)
# Multiple words
text2 = "The quick brown fox"
words = re.findall(r"\b\w+\b", text2)
print(f"\nWords in '{text2}':")
for word in words:
print(f" {word}")
# Line anchors with multiline
text3 = """line1
line2
line3"""
print("\nMultiline mode:")
matches = re.findall(r"^line", text3, re.MULTILINE)
print(f"Lines starting with 'line': {matches}")
text ← hello world, text2 ← The quick brown fox, words ← ['The', 'quick', 'brown', 'fox']
6# ^ (start of string)7print("Start anchor ^:")8print("'hello' matches ^hello:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"^hello", "hello") is not None)9print("'hello world' matches ^hello:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"^hello", "hello world") is not None)10print("'world hello' matches ^hello:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"^hello", "world hello") is not None)1112# $ (end of string)13print("\nEnd anchor $:")14print("'hello' matches hello$:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"hello$", "hello") is not None)15print("'hello world' matches world$:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"world$", "hello world") is not None)16print("'world hello' matches world$:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"world$", "world hello") is not None)1718# Both anchors19print("\nBoth anchors ^...$:")20print("'hello' matches ^hello$:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"^hello$", "hello") is not None)21print("'hello world' matches ^hello$:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"^hello$", "hello world") is not None)2223# \b (word boundary)24print(r"\nWord boundary \b:")25text→ hello world = "hello world"26print(f"Text: '{texthello world}'")27print(r"\bhello\b found:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"\bhello\b", texthello world) is not None)28print(r"\bworld\b found:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"\bworld\b", texthello world) is not None)29print(r"\bhello\b in 'helloworld':", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"\bhello\b", "helloworld") is not None)3031# Practical examples32print("\nPractical validation:")3334# Must start with letter35print("'abc123' starts with letter:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"^[a-zA-Z]", "abc123") is not None)36print("'123abc' starts with letter:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.match(r"^[a-zA-Z]", "123abc") is not None)3738# Must end with digit39print(r"'abc123' ends with digit:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"\d$", "abc123") is not None)40print(r"'abc' ends with digit:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"\d$", "abc") is not None)4142# Exact length43print(r"'12345' is exactly 5 digits:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"^\d{5}$", "12345") is not None)44print(r"'1234' is exactly 5 digits:", re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.fullmatch(r"^\d{5}$", "1234") is not None)4546# Multiple words47text2→ The quick brown fox = "The quick brown fox"48words→ ['The', 'quick', 'brown', 'fox'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"\b\w+\b", text2The quick brown fox)49print(f"\nWords in '{text2The quick brown fox}':")50for word in words:outputStart anchor ^: 'hello' matches ^hello: True 'hello world' matches ^hello: True 'world hello' matches ^hello: False End anchor $: 'hello' matches hello$: True 'hello world' matches world$: True 'world hello' matches world$: False Both anchors ^...$: 'hello' matches ^hello$: True 'hello world' matches ^hello$: False \nWord boundary \b: Text: 'hello world' \bhello\b found: True \bworld\b found: True \bhello\b in 'helloworld': False Practical validation: 'abc123' starts with letter: True '123abc' starts with letter: False 'abc123' ends with digit: True 'abc' ends with digit: False '12345' is exactly 5 digits: True '1234' is exactly 5 digits: False Words in 'The quick brown fox':for word in words:
pass 1 of 449print(f"\nWords in '{text2}':")50for wordThe in words['The', 'quick', 'brown', 'fox']:51 print(f" {wordThe}")output TheAll 4 passes — pass 1 is the card above pass word1 The 2 quick 3 brown 4 fox text3 ← line1 line2 line3, matches ← ['line', 'line', 'line']
53# Line anchors with multiline54text3→ line1 line2 line3 = """line155line256line3"""57print("\nMultiline mode:")58matches→ ['line', 'line', 'line'] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"^line", text3line1 line2 line3, re.MULTILINEre.MULTILINE)59print(f"Lines starting with 'line': {matches['line', 'line', 'line']}")output Multiline mode: Lines starting with 'line': ['line', 'line', 'line']
anchors
Matching positions with ^ (start), $ (end), and \\b (word boundary)
Groups
groups.py
Replay: real traced execution (multi-file project)
# Groups and capturing
import re
# Groups with ()
# Basic grouping
date = "2025-01-29"
pattern = re.compile(r"(\d{4})-(\d{2})-(\d{2})")
match = pattern.match(date)
if match:
print(f"Full match: {match.group(0)}")
print(f"Year: {match.group(1)}")
print(f"Month: {match.group(2)}")
print(f"Day: {match.group(3)}")
# Email parsing
email = "user@example.com"
email_pattern = re.compile(r"([^@]+)@([^@]+)")
email_match = email_pattern.match(email)
if email_match:
print("\nEmail parts:")
print(f"Username: {email_match.group(1)}")
print(f"Domain: {email_match.group(2)}")
# Phone number
phone = "(555) 123-4567"
phone_pattern = re.compile(r"\((\d{3})\)\s(\d{3})-(\d{4})")
phone_match = phone_pattern.match(phone)
if phone_match:
print("\nPhone parts:")
print(f"Area: {phone_match.group(1)}")
print(f"Exchange: {phone_match.group(2)}")
print(f"Number: {phone_match.group(3)}")
# Multiple matches
text = "Call me at 555-1234 or 555-5678"
num_pattern = re.compile(r"(\d{3})-(\d{4})")
num_matches = num_pattern.finditer(text)
print("\nAll phone numbers:")
for match in num_matches:
print(f" {match.group(0)} (Area: {match.group(1)}, Num: {match.group(2)})")
# Named groups
url = "https://example.com"
url_pattern = re.compile(r"(?P<protocol>https?)://(?P<domain>.+)")
url_match = url_pattern.match(url)
if url_match:
print("\nURL parts (named groups):")
print(f"Protocol: {url_match.group('protocol')}")
print(f"Domain: {url_match.group('domain')}")
# Non-capturing group (?:...)
text2 = "color: red; colour: blue"
# Match both spellings but don't capture the 'u'
pattern2 = re.compile(r"colou?r:\s(\w+)")
matches2 = pattern2.findall(text2)
print(f"\nColors: {matches2}")
# Groups with findall
text3 = "2025-01-29 and 2024-12-25"
dates = re.findall(r"(\d{4})-(\d{2})-(\d{2})", text3)
print("\nAll dates (as tuples):")
for year, month, day in dates:
print(f" {year}/{month}/{day}")
# Backreferences
text4 = "hello hello"
# \1 refers to first group
duplicate = re.search(r"(\w+)\s\1", text4)
if duplicate:
print(f"\nDuplicate word found: {duplicate.group(1)}")
date ← 2025-01-29, pattern ← re.compile('(\\d{4})-(\\d{2})-(\\d{2})')
6# Basic grouping7date→ 2025-01-29 = "2025-01-29"8pattern→ re.compile('(\\d{4})-(\\d{2})-(\\d{2})') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"(\d{4})-(\d{2})-(\d{2})")9match→ <re.Match object; span=(0, 10), match='2025-01-29'> = patternre.compile('(\\d{4})-(\\d{2})-(\\d{2})').match(date2025-01-29)if match:
11if match<re.Match object; span=(0, 10), match='2025-01-29'>:12 print(f"Full match: {match<re.Match object; span=(0, 10), match='2025-01-29'>.group(0)}")13 print(f"Year: {match<re.Match object; span=(0, 10), match='2025-01-29'>.group(1)}")14 print(f"Month: {match<re.Match object; span=(0, 10), match='2025-01-29'>.group(2)}")15 print(f"Day: {match<re.Match object; span=(0, 10), match='2025-01-29'>.group(3)}")outputFull match: 2025-01-29 Year: 2025 Month: 01 Day: 29email ← user@example.com, email_pattern ← re.compile('([^@]+)@([^@]+)')
17# Email parsing18email→ user@example.com = "user@example.com"19email_pattern→ re.compile('([^@]+)@([^@]+)') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"([^@]+)@([^@]+)")20email_match→ <re.Match object; span=(0, 16), match='user@example.com'> = email_patternre.compile('([^@]+)@([^@]+)').match(emailuser@example.com)if email_match:
22if email_match<re.Match object; span=(0, 16), match='user@example.com'>:23 print("\nEmail parts:")24 print(f"Username: {email_match<re.Match object; span=(0, 16), match='user@example.com'>.group(1)}")25 print(f"Domain: {email_match<re.Match object; span=(0, 16), match='user@example.com'>.group(2)}")output Email parts: Username: user Domain: example.comphone ← (555) 123-4567, phone_pattern ← re.compile('\\((\\d{3})\\)\\s(\\d{3})-(\\d{4})')
27# Phone number28phone→ (555) 123-4567 = "(555) 123-4567"29phone_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})")30phone_match→ <re.Match object; span=(0, 14), match='(555) 123-4567'> = phone_patternre.compile('\\((\\d{3})\\)\\s(\\d{3})-(\\d{4})').match(phone(555) 123-4567)if phone_match:
32if phone_match<re.Match object; span=(0, 14), match='(555) 123-4567'>:33 print("\nPhone parts:")34 print(f"Area: {phone_match<re.Match object; span=(0, 14), match='(555) 123-4567'>.group(1)}")35 print(f"Exchange: {phone_match<re.Match object; span=(0, 14), match='(555) 123-4567'>.group(2)}")36 print(f"Number: {phone_match<re.Match object; span=(0, 14), match='(555) 123-4567'>.group(3)}")output Phone parts: Area: 555 Exchange: 123 Number: 4567text ← Call me at 555-1234 or 555-5678, num_pattern ← re.compile('(\\d{3})-(\\d{4})')
38# Multiple matches39text→ Call me at 555-1234 or 555-5678 = "Call me at 555-1234 or 555-5678"40num_pattern→ re.compile('(\\d{3})-(\\d{4})') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"(\d{3})-(\d{4})")41num_matches→ ⟨callable_iterator A⟩ = num_patternre.compile('(\\d{3})-(\\d{4})').finditer(textCall me at 555-1234 or 555-5678)4243print("\nAll phone numbers:")44for match in num_matches:output All phone numbers:for match in num_matches:
pass 1 of 243print("\nAll phone numbers:")44for match<re.Match object; span=(11, 19), match='555-1234'> in num_matches⟨callable_iterator A⟩:45 print(f" {match<re.Match object; span=(11, 19), match='555-1234'>.group(0)} (Area: {match.group(1)}, Num: {match.group(2)})")output 555-1234 (Area: 555, Num: 1234)for match in num_matches:
pass 2 of 243print("\nAll phone numbers:")44for match<re.Match object; span=(23, 31), match='555-5678'> in num_matches⟨callable_iterator A⟩:45 print(f" {match<re.Match object; span=(23, 31), match='555-5678'>.group(0)} (Area: {match.group(1)}, Num: {match.group(2)})")output 555-5678 (Area: 555, Num: 5678)url ← https://example.com, url_pattern ← re.compile('(?P<protocol>https?)://(?P<domain>.+)')
47# Named groups48url→ https://example.com = "https://example.com"49url_pattern→ re.compile('(?P<protocol>https?)://(?P<domain>.+)') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"(?P<protocol>https?)://(?P<domain>.+)")50url_match→ <re.Match object; span=(0, 19), match='https://example.com'> = url_patternre.compile('(?P<protocol>https?)://(?P<domain>.+)').match(urlhttps://example.com)if url_match:
52if url_match<re.Match object; span=(0, 19), match='https://example.com'>:53 print("\nURL parts (named groups):")54 print(f"Protocol: {url_match<re.Match object; span=(0, 19), match='https://example.com'>.group('protocol')}")55 print(f"Domain: {url_match<re.Match object; span=(0, 19), match='https://example.com'>.group('domain')}")output URL parts (named groups): Protocol: https Domain: example.comtext2 ← color: red; colour: blue, pattern2 ← re.compile('colou?r:\\s(\\w+)')
57# Non-capturing group (?:...)58text2→ color: red; colour: blue = "color: red; colour: blue"59# Match both spellings but don't capture the 'u'60pattern2→ re.compile('colou?r:\\s(\\w+)') = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.compile(r"colou?r:\s(\w+)")61matches2→ ['red', 'blue'] = pattern2re.compile('colou?r:\\s(\\w+)').findall(text2color: red; colour: blue)62print(f"\nColors: {matches2['red', 'blue']}")6364# Groups with findall65text3→ 2025-01-29 and 2024-12-25 = "2025-01-29 and 2024-12-25"66dates→ [('2025', '01', '29'), ('2024', '12', '25')] = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.findall(r"(\d{4})-(\d{2})-(\d{2})", text32025-01-29 and 2024-12-25)67print("\nAll dates (as tuples):")68for year, month, day in dates:output Colors: ['red', 'blue'] All dates (as tuples):for year, month, day in dates:
pass 1 of 267print("\nAll dates (as tuples):")68for year2025, month01, day29 in dates[('2025', '01', '29'), ('2024', '12', '25')]:69 print(f" {year2025}/{month01}/{day29}")output 2025/01/29for year, month, day in dates:
pass 2 of 267print("\nAll dates (as tuples):")68for year2024, month12, day25 in dates[('2025', '01', '29'), ('2024', '12', '25')]:69 print(f" {year2024}/{month12}/{day25}")output 2024/12/25text4 ← hello hello, duplicate ← <re.Match object; span=(0, 11), match='hello hello'>
71# Backreferences72text4→ hello hello = "hello hello"73# \1 refers to first group74duplicate→ <re.Match object; span=(0, 11), match='hello hello'> = re<module 're' from '/usr/local/lib/python3.12/re/__init__.py'>.search(r"(\w+)\s\1", text4hello hello)75if duplicate:if duplicate:
74duplicate = re.search(r"(\w+)\s\1", text4)75if duplicate<re.Match object; span=(0, 11), match='hello hello'>:76 print(f"\nDuplicate word found: {duplicate<re.Match object; span=(0, 11), match='hello hello'>.group(1)}")output Duplicate word found: hello
groups
Capturing and extracting parts of matches with parentheses
Common Functions
re.match(): Match at startre.search(): Find pattern anywherere.findall(): Find all matchesre.sub(): Replace matches
Exercise: practical.py
Build validators for usernames, emails, phones, and URLs using regex