Skip to main content

REAL — linear-time (ReDoS-safe) regex engine with an re-compatible API

Project description

REAL

Regular Expression Algorithmic Library — a header-only C++20 regex engine, constexpr from end to end, with an re-compatible Python binding.

  • Linear time, always. The engine is a Pike VM (Thompson NFA simulation): no backtracking, ReDoS-safe by construction.
  • Constexpr-friendly. Patterns known at compile time are parsed, compiled and matched at compile time.
  • Minimal memory. Static (sizes fixed at compile time, zero allocation), dynamic (storage sized exactly once at pattern compilation), or hybrid (compile-time pattern, runtime text, zero heap allocation).
  • Zero dependencies. One include.

Unsupported syntax is rejected with real::regex_error rather than silently diverging. Deferred (and rejected): lookarounds, backreferences, atomic/possessive groups, Unicode property classes, Unicode case folding, re.X, pos/endpos. The planned next step is a lazy DFA for the dense-candidate cases where re is still ahead.

Matching is linear in the input length: a Thompson NFA simulation (Pike VM) with marked states, so a pattern such as (a+)+b cannot trigger exponential backtracking. make bench-python measures throughput against re on a set of representative workloads and asserts identical results; the figures it prints depend on the platform, the pattern and the input.

Supported syntax

Syntax Meaning
abc literal bytes (UTF-8 patterns match their UTF-8 bytes)
\. \* \\ escaped metacharacter, matched literally
. any codepoint except \n
[abc] [a-z] [^abc] character class (members must be ASCII); [^…] matches any codepoint outside the set
\d \D \w \W \s \S digit / word / space classes (ASCII sets, like Python's re.ASCII)
\n \t \r \f \v \a \0 \xHH control and hex escapes
x* x+ x? quantifiers (greedy; append ? for lazy)
x{n} x{n,} x{,m} x{n,m} counted repetition (greedy or lazy; counts capped at 1000)
a|b alternation, leftmost branch preferred
(…) (?:…) capturing / non-capturing group
(?P<name>…) (?<name>…) named capturing group (Python and .NET styles)
^ $ line/text anchors (Python semantics: $ also matches before a final \n)
\A \Z strict text start / end
\b \B word boundary / non-boundary (ASCII word characters)
(?ims) prefix global flags: i case-insensitive (ASCII), m multiline, s dotall — also real::flags on the constructor

Unicode model: matching is UTF-8 byte-based, but every construct consumes whole codepoints (multi-byte sequences compile to byte-level alternatives), so match boundaries never split a character. Class members and the \d \w \s sets are ASCII by design; [^…], \D \W \S and . do match non-ASCII codepoints.

Divergence from Python: when a nullable loop body ends with an empty iteration — e.g. (a*)* on "aa" — Python captures that final empty iteration (''); REAL, like Perl/PCRE, keeps the last non-empty one ("aa"). Group 0 is identical either way.

C++ API

#include <real/real.hpp>

real::regex rx("hello");     // runtime pattern, storage sized exactly once
rx.match("hello world");     // anchored at the start   (Python re.match)
rx.fullmatch("hello");       // whole text              (Python re.fullmatch)
rx.search("say hello");      // leftmost match anywhere (Python re.search)

match/fullmatch/search return a real::match_result: matched(), operator bool, start(g), end(g), m[g] (a std::string_view into the searched text, which must outlive the result), and the same accessors by group name (m["year"], group_index).

for (auto& m : rx.find_iter(text)) {  }      // lazy, Python finditer rules
rx.find_all(text);                            // eager vector<match_result>
rx.replace(text, "$2:$1");                    // $&, $1…, ${name}, $$ — re.sub
rx.replace(text, "#", 2);                     // count limit
rx.split(text);                               // Python re.split, with groups

Empty matches follow Python's rules: they are yielded (even right after a non-empty match) and the scan then advances one whole codepoint. find_iter/find_all cannot be called on a temporary regex, and match/search/split cannot take a temporary std::string.

Three memory modes

// Static: pattern compiled at compile time into exactly-sized constexpr
// arrays; an invalid pattern is a *compile error*.
constexpr real::static_regex<"(\\d{4})-(\\d{2})"> date;
static_assert(date.search("on 2026-06-10")[1] == "2026");  // constexpr match

// Hybrid: compile-time pattern, runtime text — matching performs zero heap
// allocations (state lives on the stack).
date.search(runtime_text);

// Dynamic: everything at runtime; the program is sized exactly once at
// compilation, match state is per-run scratch.
real::regex rx2(user_pattern, real::flags::icase);

The pure library is standard C++20 with no platform dependencies. real::real is the CMake FetchContent/find_package target.

Python binding

An re-compatible module backed by the C++ engine (CPython Limited API, one abi3 extension, zero dependencies):

import real

real.search(r"(?P<y>\d{4})-(?P<m>\d{2})", "on 2026-06-10").groupdict()
real.compile(r"\w+").findall(text)         # findall/finditer/split/sub/subn
real.sub(r"\s+", " ", text)                # templates: \1, \g<name>, callables
real.compile(rb"[^;]+").findall(raw)       # bytes patterns: raw-byte semantics

str matching is UTF-8 with character indices in start/end/span; bytes patterns get re's exact raw-byte semantics. Unsupported re features raise real.error at compile time. Build with make python && make python-test.

pip install real-regex installs one cp310-abi3 wheel per platform (CPython 3.10+; the self-contained sdist compiles where no wheel matches).

Embedding the C++ library through the Python package

The wheel also ships the C++ headers, so a project can compile against REAL located through its Python install — the convention used by petsc4py and slepc4py:

c++ -std=c++20 $(python -c "import real; print(real.get_include())") app.cpp

real.get_config() returns the version, the include directory and the required C++ standard.

Releasing. Run make release. It computes the next calendar version YYYY.M.PATCH — the patch resets each month, the first release of a month is .0 (PEP 440 drops leading zeros, so 2026.6.1, never 2026.06.001) — bumps it in pyproject.toml and python/real/__init__.py, then commits, tags and pushes. The tag drives release.yml, which checks the tag matches the version, builds abi3 wheels (cibuildwheel, Linux/macOS/Windows) and the sdist, and publishes to PyPI via Trusted Publishing (OIDC, no stored secret). The pushed tag is the single thing that triggers a publish.

Development

make help       # list all targets
make test       # build and run the test suite
make coverage   # line coverage report (LLVM)
make sanitize   # tests under ASan + UBSan
make lint       # clang-tidy
make misra      # MISRA C++:2023-oriented analysis
make fuzz       # libFuzzer robustness fuzzing (clang)
make doc        # API reference (Doxygen)

The API reference is published at https://reche23.github.io/real-regex/.

Select the compiler with make test CXX=g++-14. Every behaviour is tested at runtime and in constexpr (static_assert) under Clang and GCC; an equivalence suite checks the prefilter and fast paths never change results; a parity suite and a randomized differential fuzzer compare Python outputs against re.

CI exercises:

Platform Architecture Compiler
Linux x86-64 GCC, Clang
Linux AArch64 GCC
macOS Apple Silicon (arm64) Apple Clang
Windows x86-64 MSVC

IntelLLVM (icpx), x86-64 macOS and the BSDs share the Clang flag set and are supported by the build configuration but not exercised in CI.

License

MIT — Copyright (c) 2026 René Chenard

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

real_regex-2026.6.1.tar.gz (60.8 kB view details)

Uploaded Source

Built Distributions

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

real_regex-2026.6.1-cp310-abi3-win_amd64.whl (279.0 kB view details)

Uploaded CPython 3.10+Windows x86-64

real_regex-2026.6.1-cp310-abi3-win32.whl (276.6 kB view details)

Uploaded CPython 3.10+Windows x86

real_regex-2026.6.1-cp310-abi3-musllinux_1_2_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ x86-64

real_regex-2026.6.1-cp310-abi3-musllinux_1_2_aarch64.whl (1.5 MB view details)

Uploaded CPython 3.10+musllinux: musl 1.2+ ARM64

real_regex-2026.6.1-cp310-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (519.8 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.24+ x86-64manylinux: glibc 2.28+ x86-64

real_regex-2026.6.1-cp310-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl (512.0 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.24+ ARM64manylinux: glibc 2.28+ ARM64

real_regex-2026.6.1-cp310-abi3-macosx_11_0_x86_64.whl (90.2 kB view details)

Uploaded CPython 3.10+macOS 11.0+ x86-64

real_regex-2026.6.1-cp310-abi3-macosx_11_0_arm64.whl (86.8 kB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

Details for the file real_regex-2026.6.1.tar.gz.

File metadata

  • Download URL: real_regex-2026.6.1.tar.gz
  • Upload date:
  • Size: 60.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for real_regex-2026.6.1.tar.gz
Algorithm Hash digest
SHA256 5a1be2153519ba9356aae3d349af4ec5930d69ffa15a9ba47efe6c38b092474c
MD5 5f746e82c089793418ba4e18f160c615
BLAKE2b-256 5bbfeb1582a79069043cc2b2875a871c4564173f6f4f45979cd9464cdcd87cf6

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.1.tar.gz:

Publisher: release.yml on RECHE23/real-regex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file real_regex-2026.6.1-cp310-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.1-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 aeb5f9790e8d3591c97f48b19fdb6f3a80cb89d9652cd6bdc905cc3adf982cb9
MD5 75323c8f6c0a70b52d4101d251010cf5
BLAKE2b-256 181c0c3ecff689ed20bcde39ec02ca60c34258301e8e4865a689302aaea33dbd

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.1-cp310-abi3-win_amd64.whl:

Publisher: release.yml on RECHE23/real-regex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file real_regex-2026.6.1-cp310-abi3-win32.whl.

File metadata

  • Download URL: real_regex-2026.6.1-cp310-abi3-win32.whl
  • Upload date:
  • Size: 276.6 kB
  • Tags: CPython 3.10+, Windows x86
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for real_regex-2026.6.1-cp310-abi3-win32.whl
Algorithm Hash digest
SHA256 dcc5524f12cdfc9a68d617c8b5d5c7c5a827c13b1b7c46227ba7b1add579fa29
MD5 5fe8c6874860aa2f09cf7c01716a2706
BLAKE2b-256 b37538241d062b83447e195cd05f422930a617a9e50171729862be5412bbbe9e

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.1-cp310-abi3-win32.whl:

Publisher: release.yml on RECHE23/real-regex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file real_regex-2026.6.1-cp310-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.1-cp310-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 9b2f01f603fcdddc28bdcc572b28573ea4370d0305acecec23a57b34b319e71a
MD5 6c810cb08be4ec7745225f66ee8bca65
BLAKE2b-256 43346fd5f6b893531a2df87bbfc520f88cb9ab3badba86b661aa4cf714fe5b78

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.1-cp310-abi3-musllinux_1_2_x86_64.whl:

Publisher: release.yml on RECHE23/real-regex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file real_regex-2026.6.1-cp310-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.1-cp310-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 7fe59e1346c6497c308d4c5480718a7ef9ff8a6df079cf92f0401c067f479ddc
MD5 41c10cf6f28d27f9c400ce99264d9fcf
BLAKE2b-256 22847e682ce1de5672529250aeebe20d7fa952eeec8fad329970fb0dbc4cc809

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.1-cp310-abi3-musllinux_1_2_aarch64.whl:

Publisher: release.yml on RECHE23/real-regex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file real_regex-2026.6.1-cp310-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.1-cp310-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8deb8b16847492f55ec1ef72886b7488e8a1e7878b68042285eb0e7b4d0f6443
MD5 5c1e16f06de04c56352047e80cbcfe29
BLAKE2b-256 e1a18608482c84f064f4b846f2bca914639dc78868af3bf1d1c0c962527d605b

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.1-cp310-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl:

Publisher: release.yml on RECHE23/real-regex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file real_regex-2026.6.1-cp310-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.1-cp310-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 73021fe68c70c4811e58a91f1c25d8c3c66a9b1392ecdedac0a9956dde9993a5
MD5 1059497c7efe96f62035db8dee33dd80
BLAKE2b-256 15f5ca9b301c0a26adbef08eeb0628f1491c43eb151ddd81633975ece1b5fe1a

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.1-cp310-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl:

Publisher: release.yml on RECHE23/real-regex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file real_regex-2026.6.1-cp310-abi3-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.1-cp310-abi3-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 a4b0d6b6d709d27acf350958a77aa22c6a06ad8b4d5fe02ba05f80bdce3f1f2f
MD5 cb6df4c1f8f286410ebb151bb87a26c2
BLAKE2b-256 0c933b18ea959689fdba9d1fbc41a0c45492da74d07474437dd0c7e85fcdbd9e

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.1-cp310-abi3-macosx_11_0_x86_64.whl:

Publisher: release.yml on RECHE23/real-regex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file real_regex-2026.6.1-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.1-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c3946c2936d62cc30e6f77d5f15dcec1cd716edeabb5bca63d67831a691839d8
MD5 6b2aa093c644dbd5ae4cf93cb4d03bc4
BLAKE2b-256 69b1494cdbb5b8b1f0c98ee01f028589ad2907fa260b9f5354d568bf23e9fb76

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.1-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on RECHE23/real-regex

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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