Support types#

Synopsis#

The native engine’s public auxiliary types: flags (the compile options and their inline-letter equivalents), match_semantics (which match a search returns), fixed_string (the compile-time pattern literal behind static_regex), and regex_error with its machine-readable error_kind (the exception every rejection raises – never a silent divergence). Data types: no runtime cost of their own.

The everyday flags are icase, multiline, dotall, ascii and verbose – the same letters as (?imsxa) in the pattern. bytes, ecma, dollar_endonly, allow_raw_byte and ungreedy exist for drop-in parity with another surface; you rarely set them on real::regex directly.

Interface#

enum class real::flags : std::uint16_t#

Compilation flags, mirroring Python’s re.I, re.M and re.S.

Combinable with operator|. Case folding under flags::icase is Unicode in text mode and ASCII-only under flags::ascii (same split as the enumerator below and docs/divergences).

Values:

enumerator none#

No flags.

enumerator icase#

Case-insensitive (Unicode fold in text mode; ASCII under flags::ascii).

enumerator multiline#

^ and $ also match at line boundaries.

enumerator dotall#

. also matches \n.

enumerator bytes#

Binary mode: . and [^…] match raw bytes, not codepoints.

enumerator verbose#

Verbose mode (re.X): ignore unescaped whitespace and # comments outside classes.

enumerator ecma#

ECMAScript compatibility: $ (no multiline) matches only at the very end (not before a final \n, the Python default), AND . (no dotall) also excludes \r (ECMAScript excludes \n and \r; the multi-byte U+2028/U+2029 have no byte-level effect).

enumerator ascii#

ASCII mode (re.A): \d \w \s \b stay ASCII and icase folds ASCII only, even in text mode. ., explicit classes and UTF-8 literals stay code-point-aware.

enumerator dollar_endonly#

$ (no multiline) matches only at the very end of the text, never before a final \n — the Rust/\z semantics. Unlike flags::ecma this touches $ ONLY, leaving . at the Python default. Used by the Rust binding for drop-in parity.

enumerator allow_raw_byte#

Permits \C (RE2’s raw-byte escape) outside flags::bytes too. For byte-offset-native consumers only (e.g. real::compat::re2); a \C span can land mid-codepoint. flags::bytes already allows \C.

enumerator ungreedy#

Ungreedy mode (RE2 (?U)): swap the default quantifier greediness — a bare quantifier becomes lazy and the explicit ? suffix re-inverts back to greedy ((?U)a+ matches minimally, (?U)a+? maximally). Resolved entirely at parse time into each repeat node’s lazy bit (the compiler and VM never read this flag), and scoped like the other inline letters: (?U:…), (?-U:…) and the constructor flag all work through the flag-scope stack.

enum class real::match_semantics : std::uint8_t#

Which match a search returns among those starting at the leftmost position. Opt-in: first below is what a search uses unless asked otherwise.

Values:

enumerator first#

Leftmost-first (Perl / Python re / the crate): source-order thread priority decides. Default.

enumerator longest#

Leftmost-longest (POSIX / RE2 set_longest_match): the longest overall match wins the bounds.

template<std::size_t N>
struct fixed_string#

A fixed-size string usable as a non-type template parameter.

Enables static_regex<"\d+">: the literal is captured into data at compile time.

Template Parameters:

N – Size of the character array, including the terminating NUL.

Public Functions

inline constexpr fixed_string(const char (&literal)[N])#

Captures a string literal.

Implicit by design: it is what lets a string literal be a non-type template argument; marking it explicit would defeat the purpose.

Parameters:

literal[in] The string literal to capture.

inline constexpr std::string_view view() const#

Returns a view of the string, excluding the trailing NUL.

Returns:

A view of the N-1 pattern characters.

Public Members

char data[N] = {}#

The captured characters, including the trailing NUL.

class regex_error : public std::exception#

The exception every rejected pattern throws: a message with the pattern offset it was found at, plus an error_kind a caller can branch on without parsing what. In a constexpr context (static_regex) reaching the throw is a compile-time error, the message appearing in the diagnostic trace.

Public Functions

inline regex_error(const std::string &message, std::size_t position, error_kind kind = error_kind::syntax)#

Builds the error.

Parameters:
  • message[in] Human-readable cause.

  • position[in] Byte offset in the pattern where the error was found.

  • kind[in] Whether the pattern is malformed or merely unsupported (default syntax).

inline error_kind kind() const noexcept#

Whether the pattern is malformed (syntax) or well-formed but unsupported by REAL.

Returns:

The classification.

inline const char *what() const noexcept override#

Returns the formatted error message (with position).

Returns:

The message, valid for this object’s lifetime.

inline std::size_t position() const noexcept#

Returns the byte offset in the pattern where the error was found.

Returns:

The offset into the pattern text.

enum class real::error_kind : std::uint8_t#

Whether a rejected pattern is malformed (syntax) or well formed but beyond REAL’s linear engine (unsupported).

unsupported covers a backreference, a conditional, and a lookaround that is not bounded — the constructs a linear-time engine cannot represent at all. It is a stable, machine-readable classification the C ABI exposes, so a binding never has to grep regex_error::what.

There is no native escape hatch, by design — a real::regex is the linear engine or nothing. A caller who must run such a pattern anyway constructs a real::compat::regex from real/compat/std/regex.hpp with real::compat::policy::fallback, which delegates it to std::regex and forfeits the linear-time guarantee for that pattern only.

Values:

enumerator syntax#
enumerator unsupported#

Example#

Compiled and run by the example-check gate on every push:

  // flags combine bitwise at construction (the (?imsxa) inline letters work too).
  const real::regex ci {"real", real::flags::icase};
  std::cout << ci.search("the REAL engine").matched() << "\n";  // 1

  // Every rejection raises real::regex_error -- never a silent divergence.
  bool rejected = false;
  try {
    const real::regex bad {R"((a+)\1)"};  // backreference: rejected up front
  } catch (const real::regex_error&) {
    rejected = true;
  }
  std::cout << rejected << "\n";  // 1

See also#