basic_regex#

Synopsis#

real::basic_regex is the compiled pattern – the engine’s front door, with a Python-re-shaped surface. Two aliases cover its storage policies:

  • real::regex compiles at run time: real::regex re{pattern};.

  • real::static_regex carries the pattern in its type: parsed, compiled and exactly sized at compile time, matching allocates nothing and works in constexpr – an invalid pattern is a compile error.

Lifetime and regions#

  • Group views borrow the subject: it must outlive the result. A temporary std::string is a compile error.

  • find_iter / find_all are lvalue-only – a C++20 range-for would dangle on a temporary regex.

  • match / search / fullmatch on a temporary regex return owning_result_type; bind it with auto.

  • pos / endpos are byte offsets, not a slice. \A and ^ (without multiline) still see the absolute position, so they fail when pos > 0.

Interface#

template<typename Storage>
class basic_regex#

A compiled regular expression, parameterized on its storage policy.

Storage owns the program; matching allocates only per-run scratch — and nothing at all when the storage is compile-time. Use the real::regex and real::static_regex aliases rather than this template directly.

Template Parameters:

Storage – real::detail::dynamic_storage or real::detail::static_storage.

Public Types

using result_type = basic_match_result<typename Storage::slot_storage>#

This regex’s match-result type.

using owning_result_type = basic_match_result<typename Storage::slot_storage, typename Storage::name_owner>#

What a single attempt on a temporary regex yields.

Same spans and groups as result_type, plus ownership of the name tables the regex would otherwise lend. Bind it with auto. Spelling result_type (or real::match_result) does not compile, which is the point: there is no conversion that could drop the ownership and leave dangling views.

On static_regex the two aliases are the same type: the tables have static storage duration, so a result from a temporary is already safe.

Public Functions

inline explicit constexpr basic_regex(std::string_view pattern, flags compile_flags = flags::none)#

Compiles pattern at run time (the real::regex constructor).

Parameters:
  • pattern[in] The pattern text.

  • compile_flags[in] Optional flags (merged with a leading global-flags group, (?imsxaU) or (?flags-flags)).

Throws:

real::regex_error – on an invalid or over-limit pattern.

constexpr basic_regex() = default#

Default constructor for the stateless compile-time storage (static_regex).

inline constexpr result_type match(std::string_view text) const &#

Match anchored at the start of text (Python re.match).

Parameters:

text[in] The subject text (must outlive the result).

Returns:

The match result (test with matched() / operator bool).

inline constexpr result_type fullmatch(std::string_view text) const &#

Match the entire text (Python re.fullmatch).

Parameters:

text[in] The subject text (must outlive the result).

Returns:

The match result.

inline constexpr result_type search(std::string_view text) const &#

Leftmost match anywhere in text (Python re.search).

Parameters:

text[in] The subject text (must outlive the result).

Returns:

The match result.

inline constexpr result_type match(std::string_view text, std::size_t pos, std::size_t endpos = npos) const &#

Region-aware match: anchored at pos within text[0:endpos] (Python re.match with pos / endpos). Byte offsets; pos is not a slice (see run — \A fails at pos > 0); endpos defaults to the end of text.

Parameters:
  • text[in] Subject.

  • pos[in] Byte offset the match must start at.

  • endpos[in] Byte offset the region ends at; defaults to the end of text.

Returns:

The match result; falsy when the pattern does not match at pos.

inline constexpr result_type fullmatch(std::string_view text, std::size_t pos, std::size_t endpos = npos) const &#

Region-aware fullmatch: the whole region [pos, endpos) must match.

Parameters:
  • text[in] Subject.

  • pos[in] Byte offset the region starts at.

  • endpos[in] Byte offset the region ends at; defaults to the end of text.

Returns:

The match result; falsy unless the whole region matches.

inline constexpr result_type search(std::string_view text, std::size_t pos, std::size_t endpos = npos) const &#

Region-aware search: leftmost match within [pos, endpos).

Parameters:
  • text[in] Subject.

  • pos[in] Byte offset the search starts at.

  • endpos[in] Byte offset the region ends at; defaults to the end of text.

Returns:

The leftmost match in the region; falsy when there is none.

inline constexpr result_type match(const char *text) const &#

match overload for string literals.

Parameters:

text[in] NUL-terminated text.

Returns:

The result.

inline constexpr result_type fullmatch(const char *text) const &#

fullmatch overload for string literals.

Parameters:

text[in] NUL-terminated text.

Returns:

The result.

inline constexpr result_type search(const char *text) const &#

search overload for string literals.

Parameters:

text[in] NUL-terminated text.

Returns:

The result.

inline constexpr owning_result_type match(std::string_view text) const &&#

match on a temporary regex; the result owns its name context.

Parameters:

text[in] The subject text (must outlive the result).

Returns:

The match result.

inline constexpr owning_result_type fullmatch(std::string_view text) const &&#

fullmatch on a temporary regex; the result owns its name context.

Parameters:

text[in] The subject text (must outlive the result).

Returns:

The match result.

inline constexpr owning_result_type search(std::string_view text) const &&#

search on a temporary regex; the result owns its name context.

Parameters:

text[in] The subject text (must outlive the result).

Returns:

The match result.

inline constexpr owning_result_type match(std::string_view text, std::size_t pos, std::size_t endpos = npos) const &&#

Region-aware match on a temporary regex; the result owns its name context.

Parameters:
  • text[in] Subject.

  • pos[in] Byte offset the match must start at.

  • endpos[in] Byte offset the region ends at; defaults to the end of text.

Returns:

The match result.

inline constexpr owning_result_type fullmatch(std::string_view text, std::size_t pos, std::size_t endpos = npos) const &&#

Region-aware fullmatch on a temporary regex; the result owns its name context.

Parameters:
  • text[in] Subject.

  • pos[in] Byte offset the region starts at.

  • endpos[in] Byte offset the region ends at; defaults to the end of text.

Returns:

The match result.

inline constexpr owning_result_type search(std::string_view text, std::size_t pos, std::size_t endpos = npos) const &&#

Region-aware search on a temporary regex; the result owns its name context.

Parameters:
  • text[in] Subject.

  • pos[in] Byte offset the search starts at.

  • endpos[in] Byte offset the region ends at; defaults to the end of text.

Returns:

The match result.

inline constexpr owning_result_type match(const char *text) const &&#

match on a temporary regex, string-literal overload.

Parameters:

text[in] NUL-terminated text.

Returns:

The result.

inline constexpr owning_result_type fullmatch(const char *text) const &&#

fullmatch on a temporary regex, string-literal overload.

Parameters:

text[in] NUL-terminated text.

Returns:

The result.

inline constexpr owning_result_type search(const char *text) const &&#

search on a temporary regex, string-literal overload.

Parameters:

text[in] NUL-terminated text.

Returns:

The result.

inline constexpr basic_match_range<Storage> find_iter(std::string_view text) const &#

Lazy range over all non-overlapping matches (Python re.finditer).

Only callable on an lvalue regex: a C++20 range-for would dangle if the regex were a temporary (the range initializer dies before the loop body), so the rvalue overloads are deleted.

Parameters:

text[in] The subject text (must outlive the range).

Returns:

A basic_match_range usable directly in a range-for.

inline constexpr basic_match_range<Storage> find_iter(const char *text) const &#

find_iter overload for string literals.

Parameters:

text[in] NUL-terminated text.

Returns:

The range.

inline constexpr basic_match_range<Storage> find_iter(std::string_view text, std::size_t pos, std::size_t endpos = npos) const &#

Region-aware find_iter: iterate matches within [pos, endpos) (Python finditer with pos / endpos). endpos truncates the subject to a view so iteration stops at it; pos is the start, not a slice (see run). Byte offsets; endpos defaults to the end of text.

Parameters:
  • text[in] Subject.

  • pos[in] Byte offset iteration starts at.

  • endpos[in] Byte offset the region ends at; defaults to the end of text.

Returns:

A range over the matches in the region.

basic_match_range<Storage> find_iter(std::string_view text) const && = delete#

Deleted: find_iter on a temporary regex would dangle.

basic_match_range<Storage> find_iter(const char *text) const && = delete#

Deleted: find_iter on a temporary regex would dangle.

basic_match_range<Storage> find_iter(std::string_view text, std::size_t, std::size_t = npos) const && = delete#

Deleted: region find_iter on a temporary regex would dangle.

inline constexpr std::size_t count_matches(std::string_view text, std::size_t pos = 0, std::size_t endpos = npos) const#

Count non-overlapping matches without allocating result objects.

Prefer this over walking find_iter when only the count is needed. Region semantics match find_iter &#8212; pos is a start offset, not a slice (\\A / ^ still see the absolute position).

Parameters:
  • text[in] The subject text.

  • pos[in] Byte offset to begin counting from (0 = start of text).

  • endpos[in] Exclusive end of the region; npos = end of text.

Returns:

The number of non-overlapping matches in the region.

inline constexpr std::vector<result_type> find_all(std::string_view text) const &#

All matches, eagerly (like Python re.findall, but full results).

Lvalue-only, same reason as find_iter. High match counts allocate one result per hit; prefer count_matches when only the number matters, and find_iter when you can stream.

Parameters:

text[in] The subject text (must outlive the results).

Returns:

A vector of match results.

inline constexpr std::vector<result_type> find_all(const char *text) const &#

find_all overload for string literals.

Parameters:

text[in] NUL-terminated text.

Returns:

The results.

std::vector<result_type> find_all(std::string_view text) const && = delete#

Deleted: find_all on a temporary regex would dangle.

std::vector<result_type> find_all(const char *text) const && = delete#

Deleted: find_all on a temporary regex would dangle.

inline constexpr std::string replace(std::string_view text, std::string_view replacement, std::size_t max_count = 0) const#

Replaces matches in text (ECMAScript / std::regex_replace $1).

The replacement may reference groups: $$ → ‘$’, $& or $0 → whole match, $1 …, and ${name}. This is not Python re.sub (\1 / \g<name>) — that spelling is the Python and Go bindings. Returns an owning string, so a temporary text is fine here.

Parameters:
  • text[in] The subject text.

  • replacement[in] The replacement template.

  • max_count[in] Maximum replacements (0 = all).

Throws:

real::regex_error – on a malformed group reference in replacement.

Returns:

The resulting string.

inline constexpr std::vector<std::string_view> split(std::string_view text, std::size_t max_splits = 0) const#

Splits text on matches (Python re.split).

Each capturing group’s text is inserted after its split (an unset group yields an empty view, where Python would use None).

Parameters:
  • text[in] The subject text (must outlive the returned views).

  • max_splits[in] Maximum splits (0 = split everywhere).

Returns:

The pieces, with captured separators interleaved.

inline constexpr std::vector<std::string_view> split(const char *text, std::size_t max_splits = 0) const#

split overload for string literals.

Parameters:
  • text[in] NUL-terminated text.

  • max_splits[in] Max splits.

Returns:

The pieces.

result_type match(const std::string &&text) const = delete#

Deleted: temporary text would dangle.

result_type fullmatch(const std::string &&text) const = delete#

Deleted: temporary text would dangle.

result_type search(const std::string &&text) const = delete#

Deleted: temporary text would dangle.

result_type match(const std::string &&text, std::size_t, std::size_t = npos) const = delete#

Deleted: temporary text would dangle.

result_type fullmatch(const std::string &&text, std::size_t, std::size_t = npos) const = delete#

Deleted: temporary text would dangle.

result_type search(const std::string &&text, std::size_t, std::size_t = npos) const = delete#

Deleted: temporary text would dangle.

basic_match_range<Storage> find_iter(const std::string &&text) const & = delete#

Deleted: temporary text would dangle.

basic_match_range<Storage> find_iter(const std::string &&text, std::size_t, std::size_t = npos) const & = delete#

Deleted: temporary text would dangle.

std::vector<result_type> find_all(const std::string &&text) const & = delete#

Deleted: temporary text would dangle.

std::vector<std::string_view> split(const std::string &&text, std::size_t max_splits = 0) const = delete#

Deleted: temporary text would dangle.

inline constexpr std::string_view pattern() const#

Returns the pattern text this regex was compiled from.

Returns:

The pattern, valid as long as this regex is alive.

inline constexpr flags compile_flags() const#

The flag set in force: constructor flags, plus a leading (?imsxa) group, minus its -removal.

regex("(?-i)a", flags::icase) reports no flags::icase and matches case-sensitively — the accessor and the engine agree.

Returns:

The effective flag set.

inline constexpr std::size_t group_count() const#

Returns the number of capturing groups (excluding group 0).

Returns:

The capturing-group count.

inline constexpr std::size_t group_index(std::string_view name) const#

Resolves a group name to its number.

Parameters:

name[in] The group name.

Returns:

The group number, or real::npos if unknown.

inline constexpr std::vector<std::pair<std::string_view, std::size_t>> named_groups() const#

All named groups as (name, number) pairs, in declaration order.

Returns:

The list of named groups.

The two aliases:

using real::regex = basic_regex<detail::dynamic_storage>#

The runtime-compiled regex type — the primary entry point.

template<fixed_string Pattern, flags F = flags::none>
using real::static_regex = basic_regex<detail::static_storage<Pattern, F>>#

A fully compile-time regex.

The pattern is parsed, compiled and exactly sized at compile time; matching allocates nothing and also works in a constexpr context. An invalid pattern is a compile error.

Template Parameters:
  • Pattern – The pattern, as a fixed_string literal.

  • F – Compilation flags.

Two result aliases go with them, both derived from the type real::regex actually returns rather than restated: real::match_result for an attempt on a live regex, which borrows its name tables, and real::owning_match_result for an attempt on a temporary one, which owns them.

Complexity#

Every matching call is guaranteed linear in the searched text – O(len(text)) – and never backtracks (ReDoS-safe by construction).

  • Allocation. real::regex allocates when it compiles. static_regex does not. count_matches allocates no result objects. replace returns an owning std::string. split and group views borrow the subject.

  • Sharing. A compiled regex is immutable and can be used from many threads. An iterator is not shared.

Example#

Compiled and run by the example-check gate on every push – tested code, not an illustration:

  // Runtime compilation -- real::regex is basic_regex over dynamic storage.
  const real::regex counter {R"((\w+): (\d+))"};

  if (const auto m = counter.search("retries: 12, errors: 3")) {
    std::cout << m[1] << " = " << m[2] << "\n";  // retries = 12
  }
  for (const auto& m : counter.find_iter("retries: 12, errors: 3")) {
    std::cout << m[0] << "\n";  // each "name: value" hit, left to right
  }

  // Compile-time compilation -- static_regex carries the pattern in its type:
  // an invalid pattern is a compile error, and matching works in constexpr.
  constexpr real::static_regex<R"((\w+)@(\w+))"> email;
  static_assert(email.search("info@example.com")[2] == "example"sv);

See also#