Drop-in for Python re#

Full drop-in, strict by defaultimport real as re and use the API you already know; every accepted pattern is guaranteed linear. An unsupported construct raises real.error instead of silently backtracking.

Adopt / swap#

import real as re   # drop-in for the standard library's re

m = re.search(r"(\w+)@(\w+)", "info@example.com")
m.group(2)          # 'example' — linear time, no backtracking cliff

API offered#

The re surface you already call is offered whole — the module functions, Pattern’s methods, Match’s accessors — same names, same shapes. Flags re.I, re.M, re.S, re.X, re.A behave the same; Unicode \w \d \s \b and IGNORECASE folding follow re in text mode.

Beyond re — flagged extensions, never silent divergences:

  • Pattern.count_matches(text) — count matches without building Match objects.

  • real.compile(pat, fallback=True) (or module-wide real.fallback = True) — delegate a rejected pattern to stdlib re for that pattern, trading its linear-time guarantee; Pattern.engine says which backend ran.

  • \p{…} property classes and the \N{U+XXXX} scalar escape — supersets that stdlib re rejects (why).

Object-level reference: Python API.

Differences & limitations#

Every intentional divergence from re — semantics, rationale, pins — lives in Differences from Python re. The one binding-specific line: \N{NAME} is resolved by Python’s unicodedata, so character-name lookup exists only on the Python surface (no C++ name table).

Comparison#

Python re is a backtracker. REAL is linear on every accepted pattern. The shared binding bench — same harness, match counts checked before timing — lives in the performance ledger; the reading is Performance.