38 template <
typename SlotStorage>
59 std::string_view pattern,
60 std::span<const detail::named_group> names)
89 template <
bool Cascade,
typename Vm>
91 std::string_view text,
95 std::string_view pattern,
96 std::span<const detail::named_group> names)
98 const bool ok {vm.template run<Cascade>(text, pos, mode,
slots_, forbid)};
109 std::string_view pattern,
110 std::span<const detail::named_group> names)
119 template <
bool Cascade,
typename Vm>
121 std::string_view text,
127 matched_ = vm.template run<Cascade>(text, pos, mode,
slots_, forbid, sem);
142 constexpr explicit operator bool()
const {
149 [[nodiscard]]
constexpr std::size_t
size()
const
159 [[nodiscard]]
constexpr std::size_t
start(std::size_t group = 0)
const
169 [[nodiscard]]
constexpr std::size_t
end(std::size_t group = 0)
const
179 [[nodiscard]]
constexpr std::string_view
operator[](std::size_t group)
const
181 const std::size_t s {
start(group)};
182 return s ==
npos ? std::string_view {} :
text_.substr(s,
end(group) - s);
190 [[nodiscard]]
constexpr std::size_t
group_index(std::string_view name)
const
193 const auto begin {
static_cast<std::size_t
>(named_group.begin)};
194 const auto length {
static_cast<std::size_t
>(named_group.end - named_group.begin)};
195 if (
pattern_.substr(begin, length) == name) {
196 return static_cast<std::size_t
>(named_group.group);
207 [[nodiscard]]
constexpr std::size_t
start(std::string_view name)
const
218 [[nodiscard]]
constexpr std::size_t
end(std::string_view name)
const
229 [[nodiscard]]
constexpr std::string_view
operator[](std::string_view name)
const
232 return g ==
npos ? std::string_view {} : (*this)[g];
241 std::span<const detail::named_group>
names_;
258 template <
typename Storage>
283 std::string_view pattern,
284 std::string_view text,
285 std::size_t start = 0,
406 template <
typename Storage>
420 std::string_view pattern,
421 std::string_view text,
422 std::size_t start = 0,
466 template <
typename Storage>
481 requires(!Storage::is_compile_time)
489 requires(Storage::is_compile_time)
529 std::size_t endpos =
npos)
const
539 std::size_t endpos =
npos)
const
549 std::size_t endpos =
npos)
const
561 return match(std::string_view(text));
571 return fullmatch(std::string_view(text));
581 return search(std::string_view(text));
606 return find_iter(std::string_view(text));
617 std::size_t endpos =
npos)
const&
619 const std::size_t end {endpos < text.size() ? endpos : text.size()};
632 std::size_t endpos =
npos)
const&
634 const std::size_t end {endpos < text.size() ? endpos : text.size()};
642 std::size_t)
const&& =
delete;
656 std::size_t =
npos)
const&& =
delete;
667 [[nodiscard]]
constexpr std::vector<result_type>
find_all(std::string_view text)
const&
669 std::vector<result_type> result;
671 result.push_back(
match);
681 [[nodiscard]]
constexpr std::vector<result_type>
find_all(
const char* text)
const&
683 return find_all(std::string_view(text));
689 [[nodiscard]] std::vector<result_type>
find_all(std::string_view text)
const&& =
delete;
693 [[nodiscard]] std::vector<result_type>
find_all(
const char* text)
const&& =
delete;
708 [[nodiscard]]
constexpr std::string
replace(std::string_view text,
709 std::string_view replacement,
710 std::size_t max_count = 0)
const
716 if (max_count != 0 && done == max_count) {
719 result.append(text.substr(last,
match.
start() - last));
724 result.append(text.substr(last));
738 [[nodiscard]]
constexpr std::vector<std::string_view>
split(std::string_view text,
739 std::size_t max_splits = 0)
const
741 std::vector<std::string_view> result;
745 if (max_splits != 0 && done == max_splits) {
748 result.push_back(text.substr(last,
match.
start() - last));
749 for (std::size_t group = 1; group <
match.
size(); ++group) {
750 result.push_back(
match[group]);
755 result.push_back(text.substr(last));
765 [[nodiscard]]
constexpr std::vector<std::string_view>
split(
const char* text,
766 std::size_t max_splits = 0)
const
768 return split(std::string_view(text), max_splits);
780 std::size_t =
npos)
const& =
delete;
781 [[nodiscard]] std::vector<result_type>
find_all(
const std::string&& text)
const& =
delete;
782 [[nodiscard]] std::vector<std::string_view>
split(
const std::string&& text,
783 std::size_t max_splits = 0)
const =
delete;
788 [[nodiscard]]
constexpr std::string_view
pattern()
const
806 return (
program_.view().slot_count / 2) - 1;
847 return first < 0 ? std::nullopt : std::optional<unsigned char>(
static_cast<unsigned char>(
first));
873 [[nodiscard]]
constexpr std::size_t
group_index(std::string_view name)
const
876 if (
name_of(named_group) == name) {
877 return static_cast<std::size_t
>(named_group.group);
887 [[nodiscard]]
constexpr std::vector<std::pair<std::string_view, std::size_t>>
890 std::vector<std::pair<std::string_view, std::size_t>> result;
892 result.emplace_back(
name_of(named_group),
static_cast<std::size_t
>(named_group.group));
908 return pattern().substr(
static_cast<std::size_t
>(named_group.
begin),
909 static_cast<std::size_t
>(named_group.
end - named_group.
begin));
924 std::string_view replacement)
const
927 while (i < replacement.size()) {
928 const char ch {replacement[i]};
935 if (i >= replacement.size()) {
936 throw regex_error(
"dangling $ in replacement", i - 1);
938 const char next_ch {replacement[i]};
939 if (next_ch ==
'$') {
943 else if (next_ch ==
'&') {
944 out.append(
match[0]);
947 else if (next_ch >=
'0' && next_ch <=
'9') {
948 std::size_t group {};
949 while (i < replacement.size() && replacement[i] >=
'0' &&
950 replacement[i] <=
'9') {
951 group = (group * 10) +
static_cast<std::size_t
>(replacement[i] -
'0');
955 throw regex_error(
"invalid group reference in replacement", i);
957 out.append(
match[group]);
959 else if (next_ch ==
'{') {
960 const std::size_t name_begin {i + 1};
961 std::size_t j {name_begin};
962 while (j < replacement.size() && replacement[j] !=
'}') {
965 if (j == replacement.size() || j == name_begin) {
966 throw regex_error(
"malformed ${name} in replacement", i);
968 const std::size_t group =
971 throw regex_error(
"unknown group name in replacement", i);
973 out.append(
match[group]);
977 throw regex_error(
"invalid $ escape in replacement", i);
991 return run(text, 0,
npos, mode);
1016 const std::size_t end {endpos < text.
size() ? endpos : text.size()};
1017 typename Storage::state_type state;
1018 typename Storage::slot_storage slots;
1022 const bool matched {prog.hints.stop_set_size >= 1
1023 ? vm.template run<true>(text.substr(0, end), pos, mode, slots, 0, sem)
1024 : vm.template run<false>(text.substr(0, end), pos, mode, slots, 0, sem)};
1025 return {text, std::move(slots), matched,
pattern(), prog.names};
1049 std::size_t endpos =
npos)
const
1070 template <fixed_
string Pattern, flags F = flags::none>
Forward iterator over the non-overlapping matches in a text.
std::string_view pattern_
Pattern text (named lookups).
value_type current_
The current match.
match_semantics sem_
leftmost-first (default) or longest (find_iter_longest).
constexpr bool operator==(const basic_match_iterator &other) const
Returns true if both denote the same position/end.
std::ptrdiff_t difference_type
Iterator traits.
std::string_view text_
The text being scanned.
constexpr const value_type & operator*() const
Returns the current match.
constexpr basic_match_iterator()=default
Constructs the end sentinel.
std::forward_iterator_tag iterator_category
Multipass: copies are independent.
bool done_
True once exhausted.
constexpr basic_match_iterator operator++(int)
Advances to the next match (post-increment).
constexpr basic_match_iterator & operator++()
Advances to the next match.
detail::program_view prog_
The program being run.
bool cascade_
OPT-C: chosen once — run the memchr-cascade class-run variant for this whole walk.
Storage::state_type state_
VM scratch, reused across the walk.
constexpr const value_type * operator->() const
Returns pointer to the current match.
constexpr void advance()
Finds the next match, applying the empty-match advance rules.
constexpr basic_match_iterator(detail::program_view prog, std::string_view pattern, std::string_view text, std::size_t start=0, match_semantics sem=match_semantics::first)
Constructs a begin iterator and finds the first match.
std::size_t pos_
Current scan offset.
std::size_t forbid_empty_until_
Empty-match guard (see pike.hpp).
A range of matches, returned by find_iter() and usable in range-for.
constexpr basic_match_iterator< Storage > begin() const
Returns an iterator to the first match.
std::string_view text_
The text to iterate.
std::string_view pattern_
Pattern text (named lookups).
constexpr basic_match_iterator< Storage > end() const
Returns the end sentinel.
detail::program_view prog_
The program being run.
constexpr basic_match_range(detail::program_view prog, std::string_view pattern, std::string_view text, std::size_t start=0, match_semantics sem=match_semantics::first)
Binds the range to a program and text.
std::size_t start_
Byte offset to begin iterating from (region support).
match_semantics sem_
leftmost-first (default) or longest.
The result of a match attempt: success, spans and captures.
constexpr std::size_t end(std::string_view name) const
Returns its end offset, or npos if unknown.
constexpr std::string_view operator[](std::size_t group) const
View of a group's matched text.
constexpr bool engine_refill_hot(Vm &vm, std::string_view text, std::size_t pos, detail::run_mode mode, std::size_t forbid, match_semantics sem=match_semantics::first)
Per-match refill for an iterator whose context is already bound via bind_context runs the VM and reco...
constexpr std::size_t start(std::string_view name) const
Returns its start offset, or npos if unknown.
constexpr basic_match_result(std::string_view text, SlotStorage slots, bool matched, std::string_view pattern, std::span< const detail::named_group > names)
Constructs a result from raw slots (used internally by the engine).
std::string_view text_
The searched text.
SlotStorage slots_
Flattened capture slots.
constexpr bool engine_refill(Vm &vm, std::string_view text, std::size_t pos, detail::run_mode mode, std::size_t forbid, std::string_view pattern, std::span< const detail::named_group > names)
Engine-internal: re-run the search into this result's OWN slot buffer, reusing its capacity....
constexpr std::string_view operator[](std::string_view name) const
Returns its matched text, empty if unknown/unset.
constexpr std::size_t start(std::size_t group=0) const
Start byte offset of a group.
constexpr std::size_t end(std::size_t group=0) const
End byte offset (exclusive) of a group.
constexpr void bind_context(std::string_view text, std::string_view pattern, std::span< const detail::named_group > names)
Binds the invariant context (subject, pattern, named groups) once. For an iterator that refills the s...
constexpr basic_match_result()=default
Constructs an empty (non-matched) result.
bool matched_
Whether a match occurred.
std::span< const detail::named_group > names_
Borrowed named-group table.
std::string_view pattern_
Pattern text (for named lookups).
constexpr std::size_t group_index(std::string_view name) const
Resolves a group name to its number.
constexpr bool matched() const
Returns true if the attempt matched.
constexpr std::size_t size() const
Returns the number of groups, including group 0 (the whole match).
A compiled regular expression, parameterized on its storage policy.
constexpr std::string_view name_of(const detail::named_group &named_group) const
Returns its name, sliced from the pattern text.
result_type search(const std::string &&text, std::size_t, std::size_t=npos) const =delete
Deleted: temporary text would dangle.
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).
constexpr result_type search(std::string_view text) const
Leftmost match anywhere in text (Python re.search).
constexpr basic_regex(std::string_view pattern, flags compile_flags=flags::none)
Compiles pattern at run time (the real::regex constructor).
Storage program_
The storage policy holding the compiled program.
result_type search_longest(std::string_view text, std::size_t pos, std::size_t endpos=npos) const
Region-aware form of search_longest — leftmost-longest search within [pos, endpos)....
constexpr detail::program_view raw_program() const
The raw compiled program, for embedders (advanced).
constexpr std::size_t group_count() const
Returns the number of capturing groups (excluding group 0).
result_type match(const std::string &&text, std::size_t, std::size_t=npos) const =delete
Deleted: temporary text would dangle.
constexpr std::size_t group_index(std::string_view name) const
Resolves a group name to its number.
basic_match_range< Storage > find_iter_longest(std::string_view, std::size_t, std::size_t) const &&=delete
Deleted: find_iter_longest on a temporary regex would dangle.
constexpr void expand_replacement(std::string &out, const result_type &match, std::string_view replacement) const
Appends replacement to out, substituting group references.
constexpr basic_match_range< Storage > find_iter_longest(std::string_view text, std::size_t pos=0, std::size_t endpos=npos) const &
Experimental leftmost-**longest** find_iter: iterate matches with POSIX (leftmost-longest) bounds rat...
constexpr result_type run(std::string_view text, std::size_t pos, std::size_t endpos, detail::run_mode mode, match_semantics sem=match_semantics::first) const
Region-aware single attempt: match over text[0:endpos] starting at pos.
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)....
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)....
constexpr std::vector< result_type > find_all(std::string_view text) const &
All matches, eagerly (like Python re.findall but full results).
constexpr bool has_first_byte_set() const noexcept
Whether first-byte filtering is useful for this pattern.
result_type fullmatch(const std::string &&text, std::size_t, std::size_t=npos) const =delete
Deleted: temporary text would dangle.
constexpr bool may_start_with(unsigned char byte) const noexcept
Whether a non-empty match can begin with byte (sound, conservative).
constexpr std::vector< std::pair< std::string_view, std::size_t > > named_groups() const
All named groups as (name, number) pairs, in declaration order.
std::vector< std::string_view > split(const std::string &&text, std::size_t max_splits=0) const =delete
Deleted: temporary text would dangle.
basic_match_range< Storage > find_iter(const char *text) const &&=delete
Deleted: find_iter on a temporary regex would dangle.
constexpr result_type match(const char *text) const
match overload for string literals.
constexpr result_type run(std::string_view text, detail::run_mode mode) const
Runs a single match attempt from offset 0 (backs match/search/fullmatch).
constexpr result_type search(const char *text) const
search overload for string literals.
basic_match_range< Storage > find_iter(std::string_view text) const &&=delete
Deleted: find_iter on a temporary regex would dangle.
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).
basic_match_range< Storage > find_iter(const std::string &&text, std::size_t, std::size_t=npos) const &=delete
Deleted: temporary text would dangle.
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.
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.
constexpr std::string_view pattern() const
Returns the pattern text this regex was compiled from.
constexpr flags compile_flags() const
Returns the effective flags (constructor flags merged with a (?ims) prefix).
constexpr result_type match(std::string_view text) const
Match anchored at the start of text (Python re.match).
result_type search_longest(std::string_view text) const
EXPERIMENTAL, opt-in: a single leftmost-**longest** search (POSIX / RE2 set_longest_match),...
constexpr std::vector< result_type > find_all(const char *text) const &
find_all overload for string literals.
constexpr result_type fullmatch(std::string_view text) const
Match the entire text (Python re.fullmatch).
constexpr basic_regex()=default
Default constructor for the stateless compile-time storage (static_regex).
constexpr result_type fullmatch(const char *text) const
fullmatch overload for string literals.
constexpr std::string replace(std::string_view text, std::string_view replacement, std::size_t max_count=0) const
Replaces matches in text (Python re.sub).
std::vector< result_type > find_all(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 match(const std::string &&text) const =delete
Deleted: temporary text would dangle.
constexpr basic_match_range< Storage > find_iter(std::string_view text) const &
Lazy range over all non-overlapping matches (Python re.finditer).
constexpr std::vector< std::string_view > split(const char *text, std::size_t max_splits=0) const
split overload for string literals.
constexpr std::optional< unsigned char > unique_first_byte() const noexcept
The single byte every non-empty match must begin with, if unique.
constexpr basic_match_range< Storage > find_iter(const char *text) const &
find_iter overload for string literals.
std::vector< result_type > find_all(const char *text) const &&=delete
Deleted: find_all on a temporary regex would dangle.
basic_match_range< Storage > find_iter(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.
std::vector< result_type > find_all(std::string_view text) const &&=delete
Deleted: find_all on a temporary regex would dangle.
The Pike VM, generic over the scratch-state container policy.
constexpr std::size_t codepoint_advance(std::string_view text, std::size_t pos)
Number of bytes from pos to the next code-point boundary, for advancing past an empty match during it...
run_mode
How a VM run is anchored.
@ search
First match anywhere (Python re.search).
@ prefix
Anchored at the start position (Python re.match).
@ full
Anchored at both ends (Python re.fullmatch).
constexpr std::size_t npos
Sentinel for "no position" / unset capture slot (akin to std::string::npos).
match_semantics
Which match a search returns among those starting at the leftmost position (an experimental,...
@ longest
Leftmost-longest (POSIX / RE2 set_longest_match): the longest overall match wins the bounds.
@ first
Leftmost-first (Perl / Python re / the crate): source-order thread priority decides....
flags
Compilation flags, mirroring Python's re.I, re.M and re.S.
The Pike VM — a Thompson NFA simulation — and its fast paths.
Compiled form of a pattern and the public flags / error types.
Storage policies: where a program lives and how scratch is allocated.
std::int32_t begin
Start offset of the name in the pattern text.
std::int32_t end
End offset (exclusive) of the name.
bool first_bytes_valid
False when an empty match is possible.
std::int16_t single_first
The unique possible first byte, or -1.
bool byte_mode
flags::bytes mode — positions are raw bytes.
std::span< const named_group > names
Named capture groups.
pattern_hints hints
Search-acceleration hints.
UTF-8 position arithmetic for match iteration.
REAL's version macros and the C++20 language-standard guard.