Table of Contents

    re Module

    PYTHON & TEXT PROCESSING

    Python re Module — The Complete Guide

    Master regular expressions in Python: pattern matching, searching, extracting, and replacing text using the built-in re module.

    Introduction

    The re module is Python's built-in library for working with regular expressions (regex) — a powerful, compact language for describing patterns in text. With re you can search for patterns, validate input (emails, phone numbers), extract specific pieces of data, split strings intelligently, and perform advanced find-and-replace operations that would be tedious or impossible with ordinary string methods.

    In one line: The re module lets you describe a pattern once and then find, validate, extract, or replace matching text anywhere.

    Real-World Analogy

    The Search Warrant

    A regular expression is like a detailed description handed to a search team: "find anyone wearing a red hat and glasses." The team (the regex engine) scans the crowd (your text) and returns everyone who fits. You describe the pattern once, and it finds every match for you.

    Prerequisites

    Before You Start

    • Python 3.x installed
    • Basic understanding of strings and string methods
    • The module is built in — just import re (no installation needed)
    • A text editor or interactive shell to test patterns
    • Optional: an online regex tester (like regex101) to visualize matches

    Getting Started

    Import the module and run your first pattern search.

    import re
    
    text = "My email is rumman@example.com"
    match = re.search(r"\w+@\w+\.\w+", text)
    
    if match:
        print("Found:", match.group())   # Found: rumman@example.com
    Tip Always use raw strings (r"...") for patterns so backslashes like \w and \d are not misinterpreted.

    Core Functions of re

    1

    re.search()

    Find the first match anywhere in the string.

    Returns a match object if the pattern is found (anywhere), or None otherwise.

    2

    re.match()

    Match only at the beginning of the string.

    Returns a match object only if the pattern matches starting at index 0.

    3

    re.findall()

    Return all non-overlapping matches.

    Gives back a list of every matching substring (or tuples if groups are used).

    Essential re Functions

    Function Purpose Returns
    re.search(p, s) First match anywhere in the string Match object or None
    re.match(p, s) Match at the start of the string Match object or None
    re.fullmatch(p, s) Match the entire string Match object or None
    re.findall(p, s) All matches as a list List of strings/tuples
    re.finditer(p, s) All matches as an iterator Iterator of match objects
    re.sub(p, r, s) Replace matches with replacement text New string
    re.split(p, s) Split string by the pattern List of strings
    re.compile(p) Pre-compile a pattern for reuse Pattern object

    Common Metacharacters & Tokens

    Token Meaning Example
    . Any character except newline a.c matches "abc", "axc"
    \d Any digit (0-9) \d\d matches "42"
    \w Word character (letter, digit, _) \w+ matches "hello_1"
    \s Whitespace (space, tab, newline) a\sb matches "a b"
    ^ Start of string / line ^Hello
    $ End of string / line end$
    * 0 or more of the previous ab* matches "a", "abbb"
    + 1 or more of the previous \d+ matches "123"
    ? 0 or 1 (optional) colou?r matches "color"/"colour"
    {n,m} Between n and m repetitions \d{2,4}
    [...] Character set [aeiou] matches a vowel
    | OR (alternation) cat|dog
    () Capturing group (\d{4})-(\d{2})

    Practical Examples

    Extract all numbers with findall

    import re
    
    text = "Order 42 shipped, 7 pending, 128 total"
    numbers = re.findall(r"\d+", text)
    print(numbers)   # ['42', '7', '128']

    Capturing groups

    import re
    
    date = "2026-08-16"
    m = re.search(r"(\d{4})-(\d{2})-(\d{2})", date)
    
    print(m.group(0))   # 2026-08-16  (whole match)
    print(m.group(1))   # 2026        (year)
    print(m.group(2))   # 08          (month)
    print(m.group(3))   # 16          (day)

    Named groups

    import re
    
    m = re.search(r"(?P<year>\d{4})-(?P<month>\d{2})", "2026-08")
    print(m.group("year"))    # 2026
    print(m.group("month"))   # 08

    Replace with re.sub

    import re
    
    text = "Call me at 123-456-7890 or 987-654-3210"
    masked = re.sub(r"\d", "*", text)
    print(masked)   # Call me at ***-***-**** or ***-***-****

    Split on multiple delimiters

    import re
    
    data = "apple, banana;cherry orange"
    parts = re.split(r"[,;\s]+", data)
    print(parts)   # ['apple', 'banana', 'cherry', 'orange']

    Compiling Patterns for Reuse

    If you use a pattern many times, re.compile() pre-compiles it for better performance and cleaner code.

    import re
    
    # Compile once
    email_pattern = re.compile(r"\w+@\w+\.\w+")
    
    emails = ["a@x.com", "invalid", "b@y.org"]
    for e in emails:
        if email_pattern.fullmatch(e):
            print(e, "is valid")

    Useful Flags

    Flag Effect
    re.IGNORECASE / re.I Case-insensitive matching
    re.MULTILINE / re.M ^ and $ match at each line
    re.DOTALL / re.S . also matches newlines
    re.VERBOSE / re.X Allow whitespace and comments in patterns
    import re
    
    text = "Hello WORLD"
    print(re.findall(r"world", text, re.IGNORECASE))   # ['WORLD']

    A Note on Performance

    A well-written regex runs in roughly linear time \(O(n)\) over input length \(n\). But catastrophic backtracking from nested quantifiers (like (a+)+) can explode to exponential time:

    \[ T_{\text{worst}} = O(2^{n}) \]

    Avoid ambiguous nested quantifiers on untrusted input to prevent this "ReDoS" pitfall.

    Best Practices

    Do This

    • Always use raw strings r"..." for patterns
    • Compile patterns you reuse with re.compile()
    • Use named groups (?P<name>...) for readability
    • Prefer specific tokens over greedy .* where possible
    • Test complex patterns on sample data before deploying
    • Avoid nested quantifiers on untrusted input (ReDoS risk)

    Common Mistakes

    Bad Forgetting the raw string: re.search("\d+", s) — the \d may be misread and cause warnings.
    Good Using a raw string: re.search(r"\d+", s).
    Bad Using re.match expecting it to find a pattern anywhere — it only matches at the start of the string.
    Good Use re.search to find a pattern anywhere in the string.

    Interview Questions

    Question Short Answer
    Difference between search and match? match checks only the start; search scans the whole string.
    What does findall return? A list of all non-overlapping matches (tuples if there are groups).
    Why use raw strings for patterns? To stop Python from interpreting backslashes before regex sees them.
    What is a capturing group? Parentheses () that capture part of a match for later retrieval.
    What is catastrophic backtracking? Exponential slowdown from ambiguous nested quantifiers — a ReDoS risk.

    Quick Revision

    Goal Function
    Find first match anywhere re.search()
    Get all matches re.findall()
    Replace text re.sub()
    Split by pattern re.split()
    Validate whole string re.fullmatch()

    Key Takeaways

    The re module gives Python powerful pattern matching for searching, extracting, validating, and replacing text. Use raw strings, pick search vs match correctly, leverage groups and flags, and compile reused patterns — while avoiding catastrophic backtracking.