The Erbsland Regular Expression Library is a secure and reliable regular expression engine for modern C++.
It is designed to be lightweight, dependency-free, and predictable, while offering solid UTF-8 and Unicode
support out of the box.
You can embed the library directly into your project to provide regular expression matching without pulling in large external dependencies. The pattern syntax is inspired by a pragmatic mix of PCRE and Python regular expressions, focusing on clarity, safety, and maintainability.
Internally, the engine implements a carefully optimized variant of Thompson’s NFA algorithm, adapted for modern C++ and robust execution under strict resource limits.
- Zero dependencies – easy to embed and audit.
- Strong focus on security and reliability.
- Full UTF-8 support with strict input validation.
- Rich regular expression syntax:
- Greedy, lazy, and possessive quantifiers
- Atomic groups
- Optional syntax compatibility with PCRE, Python, and other popular regex engines.
- Built-in time and memory limits with safe defaults.
- Solid Unicode support without relying on ICU:
- Full Unicode character classes
- Case-insensitive matching using simple case folding
- Configurable string type support:
std::stringorstd::u8string(selected at build time)
- Human-readable error messages when parsing regular expressions.
- Rich API for:
- Finding first or all matches
- Replacing text using placeholders
- Efficient coroutine-based matching.
- String-view-based processing with no unnecessary allocations.
- Abstract input interface for custom or streaming input sources.
- Diagnostic Tools:
- Disassembler to display the generated code for any pattern.
- Assembler to write custom regex engines.
This library intentionally avoids certain features to remain predictable, secure, and memory-efficient:
- To keep the memory footprint low and matching deterministic:
- No Unicode normalization
- No multi-character case folding
- No Unicode character names
- The primary goal is security, not maximum throughput:
- Matching is efficient, but not intended for workloads where regex performance is the main bottleneck.
- Regular matching is fast, but due to almost no program optimizations, strict validation of the input, and the design of the NFA algorithm, not as fast as RE2 or PCRE.
- Some advanced constructs are deliberately not supported:
- No backreferences
- No lookahead assertions
- No conditional patterns
- ✔ Stable and suitable for production use (for UTF-8 based strings).
- ✔ Public API is stable
- ✔ Tested on:
- Linux (GCC)
- macOS (Clang)
- Windows (MSVC)
- ✗ UTF-16 and UTF-32 support:
- Implemented but not fully tested. Use it at your own risk.
- Not documented.
#include <iostream>
#include <string>
#include <el/re/regex.hpp>
using namespace el::re;
int main() {
try {
auto re = RegEx::compile(R"(\d+)");
auto text = std::string{"abc 12345 xyz"};
if (auto match = re->findFirst(text); match != nullptr) {
std::cout << "Found a number: " << match->content(0) << "\n";
}
} catch (const Error &error) {
std::cerr << error.what() << "\n";
return 1;
}
return 0;
}Direct performance comparisons between regular expression engines are often misleading.
The following benchmarks are provided only as a rough indication of performance characteristics.
All benchmarks were run on an Apple M5 Max CPU and ample memory.
Important notes to put these comparisons into context:
- The Erbsland Regular Expression Library:
- Always reads and validates UTF-8 input
- Performs Unicode-aware comparisons in all modes
- The compiled program from the pattern is not optimized for performance
- Neither PCRE nor
std::regexenforce strict UTF-8 validation (for this benchmark). - “ASCII mode” in Erbsland RE only affects character class handling; input is still processed as Unicode.
std::regexis only compared for ASCII only cases, since it does not support Unicode.pcre2is compared in the non-JIT mode.
These are selected results for version 1.1.0 of the library.
shakespeare.txt (0.65 MB)
A cropped UTF-8 plain-text edition of Shakespeare's collected works, including its Project Gutenberg notice and license.
| Pattern | Library | Mode | Median (ms) | % | Bar | Matches |
|---|---|---|---|---|---|---|
| A | erbsland-re | Unicode | 18.574 | 100 | ██████████ | 114596 |
| A | pcre2 | Unicode | 6.549 | 35 | ███▌ | 114596 |
| A | erbsland-re | Ascii | 18.311 | 100 | ██████████ | 114600 |
| A | pcre2 | Ascii | 3.693 | 20 | ██ | 114600 |
| A | std::regex | Ascii | 31.090 | 170 | █████████████████ | 114600 |
| B | erbsland-re | Unicode | 15.526 | 100 | ██████████ | 19380 |
| B | pcre2 | Unicode | 1.668 | 11 | █ | 19380 |
| B | erbsland-re | Ascii | 14.550 | 100 | ██████████ | 19387 |
| B | pcre2 | Ascii | 1.570 | 11 | █ | 19387 |
| B | std::regex | Ascii | 27.278 | 187 | ██████████████████▌ | 19387 |
- A — Words:
\w+— Finds word-character runs; a basic full-corpus token scan. - B — Capitalized words:
\b[A-Z][a-z]*\b— Finds ASCII-style capitalized words using two word-boundary assertions.
amerika-monogatari.txt (0.47 MB)
The complete UTF-8 plain-text Project Gutenberg edition of Nagai Kafū's あめりか物語, containing Japanese prose, kana, kanji, punctuation, and ruby readings in parentheses.
| Pattern | Library | Mode | Median (ms) | % | Bar | Matches |
|---|---|---|---|---|---|---|
| A | erbsland-re | Unicode | 6.262 | 100 | ██████████ | 13815 |
| A | pcre2 | Unicode | 0.919 | 15 | █▌ | 13815 |
| G | erbsland-re | Unicode | 6.146 | 100 | ██████████ | 13712 |
| G | pcre2 | Unicode | 0.899 | 15 | █▌ | 13712 |
| H | erbsland-re | Unicode | 4.317 | 100 | ██████████ | 11148 |
| H | pcre2 | Unicode | 2.249 | 52 | █████ | 11148 |
| I | erbsland-re | Unicode | 4.665 | 100 | ██████████ | 27630 |
| I | pcre2 | Unicode | 3.608 | 77 | ███████▌ | 27630 |
| J | erbsland-re | Unicode | 4.573 | 100 | ██████████ | 36457 |
| J | pcre2 | Unicode | 1.431 | 31 | ███ | 36457 |
- A — Words:
\w+— Finds Unicode word-character runs across Japanese prose. - G — Unicode letter runs:
\p{L}+— Exercises Unicode general-category lookup while finding contiguous letter runs. - H — Unicode punctuation runs:
\p{P}+— Exercises Unicode general-category lookup on Japanese and Western punctuation. - I — Word boundaries:
\b— Scans for zero-width Unicode word boundaries throughout Japanese prose. - J — Kanji runs:
[一-龯]+— Finds contiguous runs in a commonly used CJK ideograph range.
| Pattern | Library | Mode | Median (ms) | % | Bar | Matches |
|---|---|---|---|---|---|---|
| L | erbsland-re | Ascii | 0.002 | 100 | ██████████ | 0 |
| L | pcre2 | Ascii | 1.076 | 53886 | ████████████████████► | 0 |
| L | std::regex | Ascii | failed | – | – | – |
| M | erbsland-re | Ascii | 0.004 | 100 | ██████████ | 0 |
| M | pcre2 | Ascii | 0.853 | 21934 | ████████████████████► | 0 |
| M | std::regex | Ascii | failed | – | – | – |
| N | erbsland-re | Ascii | 0.001 | 100 | ██████████ | 0 |
| N | pcre2 | Ascii | 0.544 | 59520 | ████████████████████► | 0 |
| N | std::regex | Ascii | failed | – | – | – |
- L — Solidus email validator:
^([^@.]|[^@.]([^@\s]*)[^@.])@([^@\s]+\.)+[^@\s]+$— A historical Solidus email validator; a rejecting dotted domain exercises ambiguous nested repetition (CVE-2021-43805). - M — Tapestry content-type validator:
^(.+)/([^;]+)(;(.+=[^;]+))*$— A historical Apache Tapestry validator; malformed parameters exercise overlapping repetitions (CVE-2022-31781). - N — Nested quantifier:
^([A-Za-z0-9]+)*$— A canonical nested-quantifier ReDoS probe; a final rejecting character forces ambiguous repetition.
- A C++20-compliant compiler:
- Clang
- GCC
- MSVC
- CMake 3.23 or newer
Copyright © 2026 Tobias Erbsland
https://erbsland.dev/
Licensed under the Apache License, Version 2.0.
You may obtain a copy at:
http://www.apache.org/licenses/LICENSE-2.0
Distributed on an “AS IS” basis, without warranties or conditions of any kind.
See the LICENSE file for full details.