Skip to main content

A fluent, composable API for building regular expressions

Project description

regex-recipes

A fluent, composable API for building regular expressions in Python. Say goodbye to cryptic regex strings and hello to readable, maintainable pattern building.

Overview

regex-recipes provides a Pythonic, object-oriented approach to constructing regular expressions. Instead of writing complex regex strings, you can use an intuitive builder API that makes your patterns clear and self-documenting.

from regex_recipes import Regex, Str, Digit, WordChar, Range

# Build an email pattern with readable, composable components
email = Regex(
    WordChar().one_or_more(),          # username
    Str("@"),
    WordChar().one_or_more(),          # domain
    Str("."),
    Range("a", "z").one_or_more()      # TLD
).ignore_case()

# Use it like a standard regex
email.match("user@example.com")  # ✓ Matches

Features

  • Fluent API: Chain methods for readable pattern construction
  • Composable Components: Combine primitives into complex patterns
  • Type-Safe: Full type hints for IDE support and runtime checking
  • Intuitive Syntax: Use + for concatenation, | for alternation
  • Operator Overloading: Natural Python expressions for regex composition
  • Pattern Reusability: Build components once, use them anywhere
  • No Dependencies: Pure Python implementation
  • Comprehensive Coverage: Support for character classes, quantifiers, anchors, groups, and lookarounds

Installation

Install from PyPI:

pip install regex-recipes

Or install with development dependencies:

pip install regex-recipes[dev]

Quick Start

Basic Literals

from regex_recipes import Regex, Str

pattern = Regex(Str("hello"))
pattern.match("hello")      # Match object
pattern.match("goodbye")    # None

Concatenation

from regex_recipes import Regex, Str, Digit, WordChar

# Using direct composition
pattern = Regex(Str("User"), Digit().one_or_more())
# Equivalent to: r"User\d+"

# Or use the + operator
pattern = Str("hello") + Str(" ") + WordChar().one_or_more()
# Equivalent to: r"hello \w+"

Alternation

from regex_recipes import Str

# Using the | operator
pattern = Str("cat") | Str("dog") | Str("bird")
# Equivalent to: r"(?:cat|dog|bird)"

Core Components

Character Classes

from regex_recipes import (
    Digit,              # \d
    WordChar,           # \w (letters, digits, underscore)
    Whitespace,         # \s
    AllChars,           # .
    CharSet,            # [abc]
    Range,              # [a-z]
)

# Single digit
pattern = Digit()

# Any word character
pattern = WordChar()

# Custom character set
pattern = CharSet("aeiou")  # Vowels

# Character range
pattern = Range("a", "z")   # Lowercase letters
pattern = Range("A", "Z")   # Uppercase letters
pattern = Range("0", "9")   # Digits (same as Digit())

Quantifiers

from regex_recipes import Digit

digit = Digit()

# Exactly one (default)
digit.repeat(1)

# Zero or more: *
digit.zero_or_more()

# One or more: +
digit.one_or_more()

# Optional (zero or one): ?
digit.optional()

# Exact count: {n}
digit.repeat(3)  # \d{3}

# Range: {n,m}
digit.repeat(2, 5)  # \d{2,5}

# At least n: {n,}
digit.repeat(3, None)  # \d{3,}

Groups & Captures

from regex_recipes import Group, NonCapturingGroup, NamedGroup, Digit

# Capturing group
group = Group(Digit().repeat(3))
# Equivalent to: (\d{3})

# Non-capturing group
group = NonCapturingGroup(Digit().repeat(3))
# Equivalent to: (?:\d{3})

# Named capturing group
group = NamedGroup("areacode", Digit().repeat(3))
# Equivalent to: (?P<areacode>\d{3})

Anchors

from regex_recipes import StartOfLine, EndOfLine, WordBoundary, Str

# Start of line: ^
pattern = StartOfLine() + Str("hello")

# End of line: $
pattern = Str("world") + EndOfLine()

# Word boundary: \b
pattern = WordBoundary() + Str("word") + WordBoundary()

Lookarounds

from regex_recipes import Lookahead, NegativeLookahead, Lookbehind, NegativeLookbehind

# Positive lookahead: (?=...)
pattern = Lookahead(Str("success"))

# Negative lookahead: (?!...)
pattern = NegativeLookahead(Str("failure"))

# Positive lookbehind: (?<=...)
pattern = Lookbehind(Str("after"))

# Negative lookbehind: (?<!...)
pattern = NegativeLookbehind(Str("before"))

Regex API

The Regex class wraps your components and provides standard regex methods:

from regex_recipes import Regex, Digit

pattern = Regex(Digit().repeat(3), "-", Digit().repeat(4))

# Match from the beginning
pattern.match("123-4567")

# Search anywhere in the string
pattern.search("Call me at 123-4567 today")

# Match the entire string
pattern.fullmatch("123-4567")

# Find all matches
pattern.findall("123-4567 and 987-6543")

# Replace matches
pattern.sub("XXX-XXXX", "Call 123-4567 now")

# Get the compiled pattern string
pattern.pattern  # r"\d{3}-\d{4}"

# Flags
pattern.ignore_case()
pattern.multiline()
pattern.dotall()

Real-World Examples

Email Validation

from regex_recipes import Regex, WordChar, Str, Range

email = Regex(
    WordChar().one_or_more(),          # Local part
    Str("@"),
    WordChar().one_or_more(),          # Domain
    Str("."),
    Range("a", "z").one_or_more()      # TLD
).ignore_case()

assert email.match("user@example.com")

Phone Number Formatting

from regex_recipes import Regex, Digit, Str, Group, NamedGroup

phone = Regex(
    Str("("),
    NamedGroup("area", Digit().repeat(3)),
    Str(")"),
    NamedGroup("exchange", Digit().repeat(3)),
    Str("-"),
    NamedGroup("line", Digit().repeat(4))
)

assert phone.fullmatch("(555)123-4567")

URL Pattern

from regex_recipes import Regex, Str, Range, WordChar, AllChars

url = Regex(
    Str("http") + (Str("s")).optional(),  # https or http
    Str("://"),
    WordChar().one_or_more(),             # Domain
    Str("."),
    Range("a", "z").one_or_more(),        # TLD
    (Str("/") + AllChars().zero_or_more()).optional()  # Optional path
).ignore_case()

assert url.match("https://example.com/path")

Hex Color Code

from regex_recipes import Regex, Str, Range, CharSet

hex_color = Regex(
    Str("#"),
    CharSet("0123456789ABCDEFabcdef").repeat(6)
)

assert hex_color.fullmatch("#FF5733")

Builder API

For more complex patterns, use the fluent Builder class:

from regex_recipes import Builder

password = (Builder()
    .digit().one_or_more()              # At least one digit
    .raw(r"[A-Z]").one_or_more()        # At least one uppercase
    .raw(r"[a-z]").one_or_more()        # At least one lowercase
    .raw(r"[!@#$%^&*]").one_or_more()   # At least one special char
    .build())

API Reference

Component Base Methods

All components inherit from Component and support:

  • build()str: Generate the regex pattern string
  • __str__()str: Same as build()
  • __add__(other)Sequence: Concatenate components
  • __or__(other)Either: Create alternation
  • zero_or_more()ZeroOrMore: Match 0+ times (*)
  • one_or_more()OneOrMore: Match 1+ times (+)
  • optional()Optional: Match 0-1 times (?)
  • repeat(n, m=None)Repeat: Match n to m times

Regex Methods

  • match(string)Match | None: Match at start of string
  • search(string)Match | None: Search anywhere
  • fullmatch(string)Match | None: Match entire string
  • findall(string)list[Any]: Find all matches
  • sub(repl, string)str: Replace all matches
  • split(string)list[str]: Split by pattern
  • ignore_case()Regex: Case-insensitive flag
  • multiline()Regex: Multiline mode
  • dotall()Regex: Dot matches newlines
  • patternstr: Get the regex pattern string

Testing

Run the test suite:

pytest tests/

With coverage:

pytest --cov=regex_recipes tests/

Development

Setup

git clone https://github.com/adityavkulkarni/regex-recipes.git
cd regex-recipes
pip install -e ".[dev]"

Code Quality

# Format code
black .

# Lint
ruff check .

# Type checking
mypy regex_recipes/

Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

v0.1.0 (Initial Release)

  • Initial release with core components
  • Fluent builder API
  • Support for character classes, quantifiers, groups, and lookarounds
  • Type hints and comprehensive documentation

Inspiration

This library is inspired by similar fluent regex builders in other languages:

Support

For questions, issues, or suggestions, please visit the GitHub Issues page.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

regex_recipes-0.1.0.tar.gz (18.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

regex_recipes-0.1.0-py3-none-any.whl (13.8 kB view details)

Uploaded Python 3

File details

Details for the file regex_recipes-0.1.0.tar.gz.

File metadata

  • Download URL: regex_recipes-0.1.0.tar.gz
  • Upload date:
  • Size: 18.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for regex_recipes-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bee37336160743a1ab62adff64ad42711635e6cc510a1811ae628583554cacb9
MD5 9a22a36f22bdd23f24dd42cfd18b2b43
BLAKE2b-256 4262bdea63bf80f16cf9cc2f416d5d92768383f67a1f159ad975082e79d9015f

See more details on using hashes here.

File details

Details for the file regex_recipes-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: regex_recipes-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.4

File hashes

Hashes for regex_recipes-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 80001d2193da61d733f12ba9ace32b5f00742e5beccfb4d7c849a76e7e58e44c
MD5 8eb9a674d8dde310e8d284020153e4d7
BLAKE2b-256 98754268b59402b6aff94004dd7074abf74390ea33afec8fda325ad1ea48fc36

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page