std::regex compatibility#
Synopsis#
real::compat – the <regex> API you already type, on the linear
engine: basic_regex (aliases regex / wregex), the regex_match
/ regex_search / regex_replace families, match_results (aliases
smatch / cmatch) and the two iterators. Which patterns run on REAL
and which fall back is the compatibility contract; migration lives in the std::regex
drop-in – this page is the object reference.
Interface#
-
template<typename CharT = char, typename Traits = std::regex_traits<CharT>>
class basic_regex# A
std::basic_regex-compatible pattern, backed byrealwhere proven, elsestd.- Template Parameters:
CharT – Character type (
char; other types route straight tostd).Traits – Regex traits (std parity).
Public Functions
-
basic_regex() = default#
An empty pattern on the std backend — the variant’s first alternative default-constructs.
-
inline explicit basic_regex(const CharT *pattern, flag_type f = regex_constants::ECMAScript, policy pol = policy::strict)#
Compiles
patternfrom a C string.- Parameters:
pattern – [in] NUL-terminated pattern text.
f – [in] Syntax options; the grammar they select may route the pattern to
std.pol – [in] Strict rejects a pattern REAL cannot represent linearly; fallback routes it to
std.
- Throws:
real::compat::regex_error – on an invalid pattern, or on a strict-policy rejection.
-
inline explicit basic_regex(const string_type &pattern, flag_type f = regex_constants::ECMAScript, policy pol = policy::strict)#
Compiles
patternfrom an owned string.- Parameters:
pattern – [in] The pattern text.
f – [in] Syntax options.
pol – [in] Rejection policy; see the C-string overload.
- Throws:
real::compat::regex_error – on an invalid pattern, or on a strict-policy rejection.
-
inline basic_regex(const CharT *pattern, std::size_t len, flag_type f = regex_constants::ECMAScript, policy pol = policy::strict)#
Compiles the first
lencharacters ofpattern, which need not be NUL-terminated.- Parameters:
pattern – [in] Pattern text.
len – [in] Its length in characters.
f – [in] Syntax options.
pol – [in] Rejection policy.
- Throws:
real::compat::regex_error – on an invalid pattern, or on a strict-policy rejection.
-
template<typename It>
inline basic_regex(It begin, It end, flag_type f = regex_constants::ECMAScript, policy pol = policy::strict)# Compiles the pattern in
[begin, end).- Parameters:
begin – [in] Start of the pattern text.
end – [in] One past its end.
f – [in] Syntax options.
pol – [in] Rejection policy.
- Throws:
real::compat::regex_error – on an invalid pattern, or on a strict-policy rejection.
-
inline std::size_t mark_count() const noexcept#
Number of marked sub-expressions (excluding group 0), as
std::basic_regex.- Returns:
The group count.
-
inline flag_type flags() const noexcept#
The flags this regex was built with.
- Returns:
Those flags.
-
inline void swap(basic_regex &other) noexcept#
Exchanges engines, flags, policy and cached state with
other.- Parameters:
other – [inout] The regex to swap with.
-
inline bool uses_real() const noexcept#
True if this regex is backed by the
realengine (vs the std fallback).- Returns:
trueif REAL’s linear engine holds it.
-
inline compat::policy policy() const noexcept#
The drop-in policy this regex was constructed with.
- Returns:
Strict or fallback.
-
inline bool nullable() const noexcept#
Whether the pattern can match the empty string (real’s
empty_match_possiblehint).Empty-match traversal (replace / iterate) follows Python’s advance rules in
real, which differ from ECMAScript. So a nullable real-backed pattern routes those operations to a lazily builtstd::regex(std_engine) — per operation, not at construction, sosearch/matchkeepreal’s linear-time guarantee even on nullable-ReDoS patterns like(a*)*.- Returns:
trueif it is nullable;regex_replacethen routes tostd, whose empty-match traversal differs from REAL’s Python-lineage one.
-
inline bool uses_real_traversal() const noexcept#
Whether replace/iterate run on the
realtraversal (real-backed AND non-nullable AND no nullable captured-repeat group). A nullable pattern delegates replace/iterate to std (the empty-match traversal differs; and iterating a nullable pattern whose per-position match cost is O(n) is O(n²) on any linear engine, so routing it buys correctness but not a linear guarantee — see the nullable note in COMPATIBILITY.md). A pattern with a capturing group that is nullable under a quantifier ((ab|)+a) is itself non-nullable as a whole, but real’s last-consuming-iteration capture (RE2/Rust/Go lineage) diverges from an ECMAScript backtracker’s extra empty final iteration on that GROUP’s span — so it routes too, for the same reason:regex_search/matchare unaffected (see the nullable-loop group-capture section of COMPATIBILITY.md — the search residue is intentional, not an oversight).- Returns:
truefor a real-backed, non-nullable pattern.
-
template<typename BidirIt, typename Alloc = std::allocator<sub_match<BidirIt>>>
class match_results# The result of a match: group sub-matches plus the prefix and suffix.
Stores both ends of the searched sequence (
first_,last_) sosuffix()and lengths are exact (the end is not derivable from a base pointer alone). Filled either fromreal’s byte offsets or copied from astd::match_resultson the fallback path.- Template Parameters:
BidirIt – A contiguous iterator into the searched sequence.
Alloc – Allocator for the sub-match vector (std parity; default suffices).
Public Functions
-
inline bool ready() const noexcept#
Whether a successful match has been stored.
- Returns:
trueonce a search or match has filled this object.
-
inline size_type size() const noexcept#
Number of marks (groups), including group 0; 0 when there was no match.
- Returns:
The sub-match count.
-
inline bool empty() const noexcept#
Whether there are no marks at all.
- Returns:
truewhen size is 0, i.e. no match was stored.
-
inline const_reference operator[](size_type n) const#
The sub-match for group
n(group 0 is the whole match). Out-of-rangenreturns a reference to an unmatched sub_match anchored at the sequence end{last_, last_, false}, exactly likestd::match_results::operator[](verified on libc++ and libstdc++) — never out-of-bounds. A token selector{2}/{5}or a negative field relies on this.- Parameters:
n – [in] Group index; 0 is the whole match.
- Returns:
That group’s sub-match, or the end-anchored unmatched one when
nis out of range.
-
inline difference_type position(size_type n = 0) const#
Start offset of group
nfrom the sequence start. For an out-of-range groupstdanchors the sub_match at the end, so the offset is the full sequence length.- Parameters:
n – [in] Group index; 0 is the whole match.
- Returns:
Its start offset from the sequence start.
-
inline difference_type length(size_type n = 0) const#
Length of group
n(0 if out of range or unmatched).- Parameters:
n – [in] Group index; 0 is the whole match.
- Returns:
Its length in characters.
-
inline string_type str(size_type n = 0) const#
Matched text of group
n(empty if out of range or unmatched).- Parameters:
n – [in] Group index; 0 is the whole match.
- Returns:
An owned copy of its text.
-
inline const value_type &prefix() const#
The unmatched prefix (sequence start up to the whole match).
- Returns:
The prefix sub-match; see rebase_prefix for what it means during iteration.
-
inline const value_type &suffix() const#
The unmatched suffix (whole match end to sequence end).
- Returns:
The suffix sub-match.
-
inline const_iterator begin() const#
Iteration over the marks, group 0 first.
- Returns:
An iterator to the first sub-match. Iterators are const, as in
std::match_results.
-
inline const_iterator end() const#
End of the mark range.
- Returns:
One past the last sub-match.
-
template<typename BidirIt>
class sub_match# A matched sub-expression: a
[first, second)range into the searched sequence.Contiguous iterators only —
sub_matchis built from byte offsets, which requires the underlying storage to be contiguous (astd::deque::iteratoris random-access but not contiguous, so it is rejected).- Template Parameters:
BidirIt – A contiguous iterator into the searched sequence.
Public Functions
-
inline difference_type length() const#
Length of the sub-match (0 if it did not participate).
- Returns:
second - first, or 0 when matched isfalse.
-
inline string_type str() const#
The matched text as an owned string (empty if it did not participate).
- Returns:
A copy of
[first, second), or an empty string when matched isfalse.
-
class regex_error : public std::regex_error#
std::regex_error-compatible exception.Thrown on two paths, both preserving the
std::regex_errorcontract:Invalid for both backends (a syntax error): real rejects, and so does std — the exact std
.code()is preserved andwhat()keeps std’s message, so a syntax error is byte-for-bytestd.Strict-policy rejection (policy): a pattern real cannot represent linearly but std could (a backreference, an unbounded lookaround, a POSIX class) —
code()iserror_complexityandwhat()carries a REAL-identifiable message. Underpolicy::fallbackthis path delegates to std instead of throwing, so the only thrown case there is the invalid-for-both one above.
Public Functions
-
inline explicit regex_error(const std::regex_error &error)#
From a std backend error (the fallback path); keeps std’s exact code.
- Parameters:
error – [in] The standard library error to adopt.
-
inline regex_error(std::regex_constants::error_type code, std::string message)#
With an explicit code and message — the strict-policy rejection of a pattern REAL cannot represent linearly (
error_complexity), carrying a REAL-identifiable message.- Parameters:
code – [in] The
std::regex_constants::error_typeto report.message – [in] The text what returns.
-
inline const char *what() const noexcept override#
The message, which for a strict-policy rejection identifies REAL as the source.
- Returns:
A NUL-terminated message valid for this object’s lifetime.
-
template<typename BidirIt, typename CharT = typename std::iterator_traits<BidirIt>::value_type, typename Traits = std::regex_traits<CharT>>
class regex_iterator# Iterates the non-overlapping matches of a pattern in a sequence (
std::regex_iterator).Same per-operation routing as
regex_replace— a real-backed, non-nullable pattern drivesreal’s linear traversal (repeated region search — a non-nullable pattern never matches empty, so the position always advances past the match and the ECMAScript andrealsequences agree); the std backend and nullable patterns wrapstd::regex_iterator(whose empty-match advance is ECMAScript’s). The default-constructed iterator is the end sentinel.- Template Parameters:
BidirIt – A contiguous iterator into the searched sequence.
Public Functions
-
regex_iterator() = default#
Constructs the end sentinel.
-
inline regex_iterator(BidirIt first, BidirIt last, const regex_type &re, regex_constants::match_flag_type flags = regex_constants::match_default)#
Constructs a begin iterator over
[first, last)and finds the first match. A constraining match flag (see detail::real_honors) routes to the std backend, which carries the flags through the wrappedstd::regex_iterator.- Parameters:
first – [in] Start of the character sequence.
last – [in] End of the character sequence.
re – [in] The pattern; it must outlive this iterator.
flags – [in] Match flags, defaulting to
regex_constants::match_default.
-
inline regex_iterator(const regex_iterator &other)#
Copies the iteration position, but NOT the walker.
The walker is an accelerator over real_pos_, never the state itself, and that is what makes this cheap where the obvious designs are not. Copying it would clone the VM scratch it embeds; sharing it copy-on-write would clone on the first advance, which
operator++(int)performs on every call — buying++itat the price ofit++. Leaving the copy without one costs it a single walker construction IF it ever advances, and nothing at all if it does not, which is what a post-increment’s discarded result actually does.- Parameters:
other – [in] The iterator to copy.
-
regex_iterator(regex_iterator&&) noexcept = default#
Moves the walker along with the position.
-
regex_iterator(BidirIt first, BidirIt last, const regex_type &&re, regex_constants::match_flag_type flags = regex_constants::match_default) = delete#
Constructing from a temporary regex would dangle (std::regex_iterator parity).
-
inline reference operator*() const#
The current match.
- Returns:
A reference to it, valid until the next increment.
-
inline regex_iterator &operator++()#
Advances to the next match, becoming the end sentinel when there is none.
- Returns:
*this.
-
inline regex_iterator operator++(int)#
Advances to the next match, returning the previous position.
- Returns:
A copy of
*thisas it was before the increment.
-
inline bool operator==(const regex_iterator &other) const#
Equality. Two non-end iterators compare equal only for the same regex, sequence, flags and current match — not for a coincidental same position across different patterns.
- Parameters:
other – [in] The iterator to compare against.
- Returns:
Whether the two denote the same iteration position.
-
template<typename BidirIt, typename CharT = typename std::iterator_traits<BidirIt>::value_type, typename Traits = std::regex_traits<CharT>>
class regex_token_iterator# Enumerates selected sub-matches (or the text between matches) —
std::regex_token_iterator.Wraps
regex_iterator, so it inherits the per-operation nullable routing untouched (it never replays the engine choice). For each match it yields the requested fields in order: a fieldN >= 0is capture groupN(a non-participating group yields an emptymatched == falsetoken); the field-1is the text before this match since the previous one — i.e. the match’sprefix()— which turns-1into a splitter. After the last match, a trailing-1field yields the final suffix iff it is non-empty (std’s rule; an empty field between adjacent matches is still produced, the asymmetry std pins). With-1and no match at all, the whole sequence is the single token.- Template Parameters:
BidirIt – A contiguous iterator into the searched sequence.
Public Functions
-
regex_token_iterator() = default#
Constructs the end sentinel.
-
inline regex_token_iterator(BidirIt first, BidirIt last, const regex_type &re, int submatch = 0, regex_constants::match_flag_type flags = regex_constants::match_default)#
Selects a single sub-match field (
0= whole match,N= group N,-1= split).- Parameters:
first – [in] Start of the character sequence.
last – [in] End of the character sequence.
re – [in] The pattern; it must outlive this iterator.
submatch – [in] The field to yield per match.
flags – [in] Match flags, defaulting to
regex_constants::match_default.
-
inline regex_token_iterator(BidirIt first, BidirIt last, const regex_type &re, const std::vector<int> &submatches, regex_constants::match_flag_type flags = regex_constants::match_default)#
Selects a list of fields, cycled per match (e.g.
{1, 2},{-1}). The match flags are forwarded to the wrappedregex_iterator, so the nullable/honors routing is inherited.- Parameters:
first – [in] Start of the character sequence.
last – [in] End of the character sequence.
re – [in] The pattern; it must outlive this iterator.
submatches – [in] The fields to cycle through; an empty list is treated as
{0}.flags – [in] Match flags, defaulting to
regex_constants::match_default.
-
inline regex_token_iterator(BidirIt first, BidirIt last, const regex_type &re, std::initializer_list<int> submatches, regex_constants::match_flag_type flags = regex_constants::match_default)#
Selects a list of fields from a braced list (e.g.
{-1}).- Parameters:
first – [in] Start of the character sequence.
last – [in] End of the character sequence.
re – [in] The pattern; it must outlive this iterator.
submatches – [in] The fields to cycle through.
flags – [in] Match flags, defaulting to
regex_constants::match_default.
-
regex_token_iterator(BidirIt first, BidirIt last, const regex_type &&re, int submatch = 0, regex_constants::match_flag_type flags = regex_constants::match_default) = delete#
Constructing from a temporary regex would dangle (std::regex_token_iterator parity).
-
regex_token_iterator(BidirIt first, BidirIt last, const regex_type &&re, const std::vector<int> &submatches, regex_constants::match_flag_type flags = regex_constants::match_default) = delete#
This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
-
inline reference operator*() const#
The current token.
- Returns:
A reference to it, valid until the next increment.
-
inline regex_token_iterator &operator++()#
Advances to the next token, becoming the end sentinel when the fields are exhausted.
- Returns:
*this.
-
inline regex_token_iterator operator++(int)#
Advances to the next token, returning the previous position.
- Returns:
A copy of
*thisas it was before the increment.
-
inline bool operator==(const regex_token_iterator &other) const#
Equality. Two non-end iterators compare equal only for the same underlying walk, field selectors, field index, suffix state and current token.
- Parameters:
other – [in] The iterator to compare against.
- Returns:
Whether the two denote the same iteration position.
Matching and replacing#
The <regex> free functions ship with their full standard overload sets
(C strings, std::string, iterator pairs, with or without a
match_results):
regex_match– the whole range must match.regex_search– leftmost match anywhere in the range.regex_replace– template substitution over every match.
Their complete signatures render in the Doxygen namespace reference:
Constants and policy#
The <regex> constants the constructors and free functions take, and the
policy knob that picks strict rejection or the std::regex fallback:
-
enum real::compat::regex_constants::syntax_option_type#
Grammar / option flags (own bit values; mapped to real::flags or std at construction).
Values:
-
enumerator ECMAScript#
The default grammar.
-
enumerator icase#
Case-insensitive (ASCII).
-
enumerator nosubs#
Do not expose sub-expressions (groups still computed).
-
enumerator optimize#
Hint to favour matching speed; honoured as a no-op.
-
enumerator collate#
Locale-sensitive ranges; forces the std backend.
-
enumerator multiline#
^/$match at line boundaries.
-
enumerator basic#
POSIX BRE — translated onto REAL when the pattern translates, else the std backend.
-
enumerator extended#
POSIX ERE — translated onto REAL when the pattern translates, else the std backend.
-
enumerator awk#
awk grammar (ERE + C escapes) — translated onto REAL when it translates, else std.
-
enumerator grep#
grep grammar (BRE, lines joined by
|) — translated onto REAL when it translates, else std.
-
enumerator egrep#
egrep grammar (ERE, lines joined by
|) — translated onto REAL when it translates, else std.
-
enumerator ECMAScript#
-
enum real::compat::regex_constants::match_flag_type#
Match-control flags: the common subset.
Values:
-
enumerator match_default#
No constraint; the operation may stay on REAL.
-
enumerator match_not_bol#
^does not match the start of the sequence.
-
enumerator match_not_eol#
$does not match the end of the sequence.
-
enumerator match_not_bow#
\bdoes not match at the start.
-
enumerator match_not_eow#
\bdoes not match at the end.
-
enumerator match_any#
Any match will do; REAL satisfies it by returning the leftmost one.
-
enumerator match_not_null#
Do not match an empty sequence.
-
enumerator match_continuous#
The match must start at the first character.
-
enumerator match_prev_avail#
--firstis valid, so^and\bmay inspect the character before it.
-
enumerator format_default#
ECMAScript replacement syntax, copying the unmatched text.
-
enumerator format_sed#
sed/POSIX replacement syntax (routes to std).
-
enumerator format_no_copy#
Do not copy the parts of the text that did not match.
-
enumerator format_first_only#
Replace only the first match.
-
enumerator match_default#
-
enum class real::compat::policy : std::uint8_t#
The drop-in policy for a pattern the linear engine cannot represent (backreferences, an unbounded lookaround, a POSIX class, …).
strict(the default) rejects it, so every accepted pattern executes eachregex_search/regex_matchin time linear in the input — the ReDoS-safety guarantee (replace/iterate compose O(n) such operations: quadratic worst-case on any linear engine, never exponential);fallbackdelegates it tostd::regex, which may accept it but forfeits the guarantee for that pattern.Values:
-
enumerator strict#
Reject an ineligible pattern (throws
regex_errorwitherror_complexity). The default.
-
enumerator fallback#
Delegate an ineligible pattern to
std::regex(backtracking — not ReDoS-safe).
-
enumerator strict#
Complexity#
A pattern the shim routes to REAL matches in guaranteed linear time – O(len(text)) – and never backtracks (ReDoS-safe). Which patterns route, and what the opt-in fallback changes, is exactly the compatibility contract.
Example#
Compiled and run by the example-check gate on every push:
namespace rc = real::compat;
const rc::regex date {R"((\d{4})-(\d{2}))"};
const std::string text {"released 2026-07-21"};
rc::smatch m;
if (rc::regex_search(text, m, date)) {
std::cout << m[1].str() << "/" << m[2].str() << "\n"; // 2026/07
}
See also#
Migration from
std::regex: the drop-in tour.The routing/fallback contract: std-regex-reference.
The native engine behind it: basic_regex.