Mojo Regular Expressions

A regular expression (regex) is a pattern that describes a set of strings. You use regexes to search for text, validate input, extract parts of strings, and replace content. Mojo accesses the full Python re module through its interop layer, giving you one of the most powerful and battle-tested regex engines available.

The Pattern-Matching Concept

  Text:    "Call us at 555-7890 or 800-1234"
  Pattern: \d{3}-\d{4}

  Matches found:
  "Call us at [555-7890] or [800-1234]"
               ─────────    ─────────
               match 1      match 2

  The pattern \d{3}-\d{4} means:
    \d{3}  → exactly 3 digits
    -      → a literal hyphen
    \d{4}  → exactly 4 digits

Importing the re Module

from python import Python

fn main() raises:
    var re = Python.import_module("re")
    print("re module loaded:", re.__name__)

Pattern Syntax Cheat Sheet

Pattern    | Matches
-----------|-----------------------------------------------
.          | Any character except newline
\d         | One digit [0-9]
\D         | One non-digit
\w         | One word character [a-zA-Z0-9_]
\W         | One non-word character
\s         | One whitespace (space, tab, newline)
\S         | One non-whitespace
^          | Start of string
$          | End of string
*          | Zero or more of preceding
+          | One or more of preceding
?          | Zero or one of preceding
{n}        | Exactly n of preceding
{n,m}      | Between n and m of preceding
[abc]      | One of: a, b, or c
[^abc]     | One character that is NOT a, b, or c
(group)    | Capture a group
a|b        | Either a or b

Checking if a Pattern Exists: re.search

from python import Python

fn main() raises:
    var re = Python.import_module("re")

    var text = "The temperature is 37.5 degrees"

    var match = re.search(r"\d+\.?\d*", text)
    if match:
        print("Number found:", match.group())   # 37.5
    else:
        print("No number found")

Matching from the Start: re.match

from python import Python

fn main() raises:
    var re = Python.import_module("re")

    # re.match only checks the beginning of the string
    var m1 = re.match(r"\d+", "42 apples")
    var m2 = re.match(r"\d+", "apples 42")

    if m1: print("m1 matched:", m1.group())   # 42
    if not m2: print("m2 not matched — no digits at start")

Finding All Matches: re.findall

from python import Python

fn main() raises:
    var re = Python.import_module("re")

    var sentence = "Prices: $12, $450, $3, $1200"
    var amounts  = re.findall(r"\$(\d+)", sentence)

    print(amounts)           # ['12', '450', '3', '1200']
    print(len(amounts))      # 4

    var total = 0
    for i in range(int(len(amounts))):
        total += int(amounts[i])
    print("Total: $" + str(total))   # Total: $1665
findall() diagram:
  Text: "Prices: $12, $450, $3, $1200"
  Pattern: \$(\d+)
                     ↑    ↑   ↑    ↑
  Captures:         12  450   3  1200
  Returns: ['12', '450', '3', '1200']

Replacing Text: re.sub

from python import Python

fn main() raises:
    var re = Python.import_module("re")

    var text = "My phone: 555-123-4567 or 800-987-6543"

    # Mask all digits with *
    var masked = re.sub(r"\d", "*", text)
    print(masked)   # My phone: ***-***-**** or ***-***-****

    # Replace phone numbers with [REDACTED]
    var redacted = re.sub(r"\d{3}-\d{3}-\d{4}", "[REDACTED]", text)
    print(redacted)   # My phone: [REDACTED] or [REDACTED]

Splitting Strings: re.split

from python import Python

fn main() raises:
    var re = Python.import_module("re")

    # Split on any whitespace or punctuation
    var csv_like = "Alice,30;Engineer|Tokyo"
    var parts = re.split(r"[,;|]", csv_like)

    for i in range(int(len(parts))):
        print(parts[i])
    # Alice
    # 30
    # Engineer
    # Tokyo

Capturing Groups

from python import Python

fn main() raises:
    var re = Python.import_module("re")

    var log_line = "2025-03-15 ERROR DatabaseConnection: timeout after 30s"
    var pattern  = r"(\d{4}-\d{2}-\d{2}) (\w+) (.+)"

    var m = re.match(pattern, log_line)
    if m:
        print("Date:    ", m.group(1))   # 2025-03-15
        print("Level:   ", m.group(2))   # ERROR
        print("Message: ", m.group(3))   # DatabaseConnection: timeout after 30s
Group diagram:
  "2025-03-15 ERROR DatabaseConnection: timeout after 30s"
   ──────────  ─────  ─────────────────────────────────────
   group(1)   group(2)            group(3)

  (\d{4}-\d{2}-\d{2})  → date
  (\w+)                 → log level
  (.+)                  → rest of line

Compiling Patterns for Speed

Compile a pattern once when you run the same regex many times — this avoids re-parsing the pattern on every call.

from python import Python

fn main() raises:
    var re = Python.import_module("re")

    # Compile once
    var email_pattern = re.compile(
        r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
    )

    var texts = List[String](
        "Contact me at alice@example.com",
        "No email here",
        "Send to bob.smith@company.org please",
    )

    for i in range(len(texts)):
        var m = email_pattern.search(texts[i])
        if m:
            print("Found:", m.group())
        else:
            print("No email in:", texts[i])

Common Regex Patterns

Use case            | Pattern
--------------------|------------------------------------------------
Email address       | [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
Phone (US)          | \(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}
Date (YYYY-MM-DD)   | \d{4}-\d{2}-\d{2}
IPv4 address        | \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
Positive integer    | \d+
Decimal number      | -?\d+\.?\d*
Hex color           | #[0-9a-fA-F]{6}
URL                 | https?://[^\s]+
HTML tag            | <[^>]+>
Whitespace run      | \s+

Key Takeaways

Import Python's re module with Python.import_module("re"). Use re.search to find a pattern anywhere in a string, re.match to match only at the start, and re.findall to extract all matches into a list. Replace text with re.sub and split strings on regex delimiters with re.split. Parentheses create capture groups accessible via match.group(n). Compile patterns with re.compile when using the same pattern repeatedly. Use raw strings (r"...") for patterns to avoid Python interpreting backslashes as escape characters.

Leave a Comment

Your email address will not be published. Required fields are marked *