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, pos/endpos.

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. A literal prefilter and several whole-pattern fast paths (literals, fixed-width sequences, ./negated-class runs, alternations of straight-line branches) keep the constant factor low without leaving the linear-time guarantee.

make bench-python compares throughput against Python's re, and make bench-engines compares against std::regex, PCRE2 and RE2 in one C++ process (each engine's match counts are checked equal). Figures depend on the platform, pattern and input; reproduce them locally rather than trusting a number here.

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)
\< \> start / end of word (REAL extension, not in Python re)
(?imsx) prefix global flags: i case-insensitive (ASCII), m multiline, s dotall, x verbose (ignore unescaped whitespace and # comments outside classes) — 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.3.tar.gz (66.5 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.3-cp310-abi3-win_amd64.whl (286.6 kB view details)

Uploaded CPython 3.10+Windows x86-64

real_regex-2026.6.3-cp310-abi3-win32.whl (284.4 kB view details)

Uploaded CPython 3.10+Windows x86

real_regex-2026.6.3-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.3-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.3-cp310-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl (524.3 kB view details)

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

real_regex-2026.6.3-cp310-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl (514.6 kB view details)

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

real_regex-2026.6.3-cp310-abi3-macosx_11_0_x86_64.whl (99.6 kB view details)

Uploaded CPython 3.10+macOS 11.0+ x86-64

real_regex-2026.6.3-cp310-abi3-macosx_11_0_arm64.whl (96.0 kB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

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

File metadata

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

File hashes

Hashes for real_regex-2026.6.3.tar.gz
Algorithm Hash digest
SHA256 af5929d59fe9c4813fa071990a3f3fc0d7e62654113c6ff6df8df0032f673dc4
MD5 2176afd80e84fddf8e89129414ca57a6
BLAKE2b-256 95f4ba24e1ed982dc287fdab4636c1f6fcdf0114532365054f957fde791c8096

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.3.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.3-cp310-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.3-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 ae0bccd96eed760fb00dbeed3d1163325fa3316f0bb4265d6b58bd47c88d5348
MD5 cfe9dfa2ee202a9d750a53ac4346d774
BLAKE2b-256 ad0f5a95549dc4bcfbaa2242b89575674901b89f160c0dc305cd2a6b07271fa3

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.3-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.3-cp310-abi3-win32.whl.

File metadata

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

File hashes

Hashes for real_regex-2026.6.3-cp310-abi3-win32.whl
Algorithm Hash digest
SHA256 fa294b4a41dafbcea2906653b10c1aea2985fd0cba06c775eede6178b2cf29be
MD5 aac4be2b3e2985e25571df12da81a420
BLAKE2b-256 52a5ccfc4c39a0fdd97305b8b871f7622f1a420486bb4927cee000e6028118ea

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.3-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.3-cp310-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.3-cp310-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 641d5896a2fa3451f6a8358071024a1a73534a911fc9193c6668f19d595c6122
MD5 36bc277a1a4811537fdd01dce7fac956
BLAKE2b-256 fefc0815756e1472b1ad5cfde55e871b0e264f810190177c5e0bad7a43392fbb

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.3-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.3-cp310-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.3-cp310-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 3183244a406697869853badbc9ea5ee71b0de78173fad715a3582d3f5e2d6d21
MD5 ad0580b227240d0a37790abb18f488f3
BLAKE2b-256 ca086cd9d9e47456eb1940453bd2d7dff3481a07d63464b1df74e2f324eb33e0

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.3-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.3-cp310-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.3-cp310-abi3-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 c114dece8b9b4528bff8c0f2043bc67afb6e41845c4e45f609d2ca2a9695dbfa
MD5 e743a0343f6c5e615bc39768ffa87133
BLAKE2b-256 b76c0e610005e22b7af97768cdc5c24f7ff27edb17b6d821da8b82009feab855

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.3-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.3-cp310-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.3-cp310-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 7a3e5c05a677af11d93d742c4620bbb9e0e70636e609e2e2fe21396657080859
MD5 69761b2b5c435343c5b52edf4f590fe7
BLAKE2b-256 5b63699ab81601f25b3991689db050e044906ac7ab8be766913e93cf44bb28a6

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.3-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.3-cp310-abi3-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.3-cp310-abi3-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 4035ca76b82fca9ee4ff03c48f455dd97c4c7b27dfd4dbceed4bff4d68c23905
MD5 a7ad16bdbcc0c3433b97323e381ed2c1
BLAKE2b-256 035d45f77ed770f5ba01e6f5d317cecef5cf90389ac77aee1a41feefb8d3ad4f

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.3-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.3-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for real_regex-2026.6.3-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 12cc41203372b21948cce483eddc8eb73db5afb90eadcc9f9b97a0c640d1dc95
MD5 08020cdc461c9678e4644cc8ded16712
BLAKE2b-256 cca2813159dcadfdfdd8c54bcf96c2e7a4460175c3b2a0a8b3521fc35a597f48

See more details on using hashes here.

Provenance

The following attestation bundles were made for real_regex-2026.6.3-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