7#ifndef REAL_STD_REGEX_MATCH_HPP
8#define REAL_STD_REGEX_MATCH_HPP
28 template <
typename B
idirIt>
31 static_assert(std::contiguous_iterator<BidirIt>,
32 "real::compat::sub_match requires a contiguous iterator");
37 using value_type =
typename std::iterator_traits<BidirIt>::value_type;
64 [[nodiscard]] std::basic_string_view<value_type>
view()
const
66 return matched ? std::basic_string_view<value_type>(std::to_address(
first),
67 static_cast<std::size_t
>(
length()))
68 : std::basic_string_view<value_type> {};
74 return str().compare(other);
79 return str().compare(other.
str());
84 template <
typename B
idirIt>
88 return lhs.
str() == rhs;
91 template <
typename B
idirIt>
95 return lhs == rhs.
str();
98 template <
typename B
idirIt>
102 return lhs.
str() == rhs.
str();
115 template <
typename B
idirIt,
typename Alloc = std::allocator<sub_match<B
idirIt>>>
127 using char_type =
typename std::iterator_traits<BidirIt>::value_type;
131 [[nodiscard]]
bool ready() const noexcept
142 [[nodiscard]]
bool empty() const noexcept
173 return (*
this)[n].str();
242 template <
typename RealMatch>
246 const std::size_t count {match.size()};
248 for (std::size_t g = 0; g < count; ++g) {
249 const std::size_t start {match.start(g)};
250 const std::size_t fin {match.end(g)};
260 const std::size_t whole_start {match.start(0)};
261 const std::size_t whole_end {match.end(0)};
264 .matched = whole_start > 0};
272 template <
typename StdMatch>
277 for (
const auto& sub : match) {
280 const auto& pre {match.prefix()};
281 const auto& suf {match.suffix()};
324 return (
static_cast<unsigned>(mf) & ~non_constraining) == 0U;
334 using namespace regex_constants;
335 constexpr unsigned honored {
static_cast<unsigned>(match_default) |
static_cast<unsigned>(match_any)
336 |
static_cast<unsigned>(format_first_only)
337 |
static_cast<unsigned>(format_no_copy)};
338 return (
static_cast<unsigned>(f) & ~honored) == 0U;
346 [[nodiscard]]
inline std::regex_constants::match_flag_type
349 namespace sc = std::regex_constants;
350 using namespace regex_constants;
351 auto s {sc::match_default};
352 if ((f & match_not_bol) != 0U) { s |= sc::match_not_bol; }
353 if ((f & match_not_eol) != 0U) { s |= sc::match_not_eol; }
354 if ((f & match_not_bow) != 0U) { s |= sc::match_not_bow; }
355 if ((f & match_not_eow) != 0U) { s |= sc::match_not_eow; }
356 if ((f & match_any) != 0U) { s |= sc::match_any; }
357 if ((f & match_not_null) != 0U) { s |= sc::match_not_null; }
358 if ((f & match_continuous) != 0U) { s |= sc::match_continuous; }
359 if ((f & match_prev_avail) != 0U) { s |= sc::match_prev_avail; }
360 if ((f & format_sed) != 0U) { s |= sc::format_sed; }
361 if ((f & format_no_copy) != 0U) { s |= sc::format_no_copy; }
362 if ((f & format_first_only) != 0U) { s |= sc::format_first_only; }
369 template <
typename B
idirIt,
typename CharT,
typename Traits>
378 if constexpr (real_eligible<CharT, Traits>) {
380 const std::string_view sv {std::to_address(
first),
381 static_cast<std::size_t
>(std::distance(
first, last))};
385 const auto result {anchored ? engine.
fullmatch(sv)
386 : (re.
posix_longest() ? engine.search_longest(sv) : engine.search(sv))};
387 if (!result.matched()) {
395 const std::basic_regex<CharT, Traits>& std_engine {re.
std_engine()};
396 std::match_results<BidirIt> std_m;
398 const bool ok {anchored ? std::regex_match(
first, last, std_m, std_engine, sf)
399 : std::regex_search(
first, last, std_m, std_engine, sf)};
409 template <
typename B
idirIt,
typename CharT,
typename Traits>
416 if constexpr (real_eligible<CharT, Traits>) {
418 const std::string_view sv {std::to_address(
first),
419 static_cast<std::size_t
>(std::distance(
first, last))};
422 : (re.
posix_longest() ? engine.search_longest(sv) : engine.search(sv)).matched();
425 const std::basic_regex<CharT, Traits>& std_engine {re.
std_engine()};
427 return anchored ? std::regex_match(
first, last, std_engine, sf)
428 : std::regex_search(
first, last, std_engine, sf);
433 template <
typename B
idirIt,
typename CharT,
typename Traits>
443 template <
typename CharT,
typename Traits>
445 match_results<
typename std::basic_string<CharT>::const_iterator>& m,
452 template <
typename CharT,
typename Traits>
458 return detail::run(s, s + std::char_traits<CharT>::length(s), m, re,
false,
flags);
461 template <
typename B
idirIt,
typename CharT,
typename Traits>
470 template <
typename CharT,
typename Traits>
478 template <
typename CharT,
typename Traits>
487 template <
typename B
idirIt,
typename CharT,
typename Traits>
497 template <
typename CharT,
typename Traits>
499 match_results<
typename std::basic_string<CharT>::const_iterator>& m,
506 template <
typename CharT,
typename Traits>
512 return detail::run(s, s + std::char_traits<CharT>::length(s), m, re,
true,
flags);
515 template <
typename B
idirIt,
typename CharT,
typename Traits>
524 template <
typename CharT,
typename Traits>
532 template <
typename CharT,
typename Traits>
543 template <
typename CharT,
typename Traits>
545 match_results<
typename std::basic_string<CharT>::const_iterator>&,
547 template <
typename CharT,
typename Traits>
549 match_results<
typename std::basic_string<CharT>::const_iterator>&,
552 template <
typename CharT,
typename Traits>
554 match_results<
typename std::basic_string<CharT>::const_iterator>&,
556 template <
typename CharT,
typename Traits>
558 match_results<
typename std::basic_string<CharT>::const_iterator>&,
574 template <
typename RealMatch>
577 std::string_view fmt,
578 std::string_view text,
579 std::size_t prefix_start)
581 const std::size_t group_count {m.size()};
582 const std::size_t whole_start {m.start(0)};
583 const std::size_t whole_end {m.end(0)};
584 for (std::size_t i = 0; i < fmt.size(); ++i) {
586 out.push_back(fmt[i]);
589 if (i + 1 >= fmt.size()) {
593 const char next {fmt[i + 1]};
598 else if (next ==
'&') {
599 out.append(text.substr(whole_start, whole_end - whole_start));
602 else if (next ==
'`') {
603 out.append(text.substr(prefix_start, whole_start - prefix_start));
606 else if (next ==
'\'') {
607 out.append(text.substr(whole_end));
610 else if (next >=
'0' && next <=
'9') {
615 std::size_t group {
static_cast<std::size_t
>(next -
'0')};
616 std::size_t consumed {1};
617 if (i + 2 < fmt.size() && fmt[i + 2] >=
'0' && fmt[i + 2] <=
'9') {
618 group = (group * 10) +
static_cast<std::size_t
>(fmt[i + 2] -
'0');
621 if (group >= 1 && group < group_count && m.start(group) !=
real::npos) {
622 out.append(text.substr(m.start(group), m.end(group) - m.start(group)));
640 template <
typename CharT,
typename Traits>
643 const std::basic_string<CharT>& fmt,
646 if constexpr (!detail::real_eligible<CharT, Traits>) {
660 const std::string_view text {s};
664 std::size_t last_end {0};
668 const auto matches {re.
posix_longest() ? engine.find_iter_longest(text) : engine.find_iter(text)};
669 for (
const auto& match : matches) {
673 const std::size_t prefix_start {last_end};
675 out.append(text.substr(last_end, match.start() - last_end));
678 last_end = match.end();
684 out.append(text.substr(last_end));
691 template <
typename CharT,
typename Traits>
701 template <
typename OutputIt,
typename B
idirIt,
typename CharT,
typename Traits>
706 const std::basic_string<CharT>& fmt,
710 return std::copy(result.begin(), result.end(), out);
constexpr bool matched() const
Returns true if the attempt matched.
A compiled regular expression, parameterized on its storage policy.
constexpr result_type fullmatch(std::string_view text) const
Match the entire text (Python re.fullmatch).
A std::basic_regex-compatible pattern, backed by real where proven, else std.
bool posix_longest() const noexcept
Whether this is a POSIX-ERE pattern routed to REAL: search/match must use leftmost-**longest** bounds...
const std::basic_regex< CharT, Traits > & std_engine() const
The std::regex for the std / lazy-std path (built once on demand for a real-backed pattern reached vi...
const std::variant< std::basic_regex< CharT, Traits >, real::regex > & engine() const noexcept
Access the active backend (engine-facing; used by the free functions).
bool uses_real_traversal() const noexcept
Whether replace/iterate run on the real traversal (real-backed AND non-nullable). A nullable pattern ...
bool uses_real() const noexcept
True if this regex is backed by the real engine (vs the std fallback).
The result of a match: group sub-matches plus the prefix and suffix.
void fill_from_real(const RealMatch &match)
Fills from real's byte offsets over the sequence [first_, last_). Templated on the match type — real:...
difference_type position(size_type n=0) const
Start offset of group n from the sequence start. For an out-of-range group std anchors the sub_match ...
typename std::iterator_traits< BidirIt >::difference_type difference_type
Distance type.
size_type size() const noexcept
Number of marks (groups), including group 0; 0 when there was no match.
const_iterator cbegin() const
BidirIt last_
End of the searched sequence.
const_iterator iterator
Iterators are const (std parity).
const_iterator end() const
bool ready_
Whether a match is stored.
std::size_t size_type
Size type.
std::vector< value_type, Alloc > groups_
Group sub-matches (0 = whole match).
value_type unmatched_
Sentinel for out-of-range operator[] (anchored at last_).
void fill_from_std(const StdMatch &match)
Copies from a std::match_results (the fallback path) over the same sequence.
BidirIt first_
Start of the searched sequence.
std::basic_string< char_type > string_type
Owning string type.
const_iterator cend() const
typename std::vector< value_type, Alloc >::const_iterator const_iterator
Iterator.
void set_ready_no_match()
Marks a ready but unmatched result — after a failed search/match std leaves ready() == true with size...
string_type str(size_type n=0) const
Matched text of group n (empty if out of range or unmatched).
const_reference operator[](size_type n) const
The sub-match for group n (group 0 is the whole match). Out-of-range n returns a reference to an unma...
typename std::iterator_traits< BidirIt >::value_type char_type
Character type.
value_type suffix_
Unmatched suffix.
bool empty() const noexcept
void rebase_prefix(BidirIt first)
Re-bases the unmatched prefix to start at first — for iteration, where a match's prefix runs from the...
void reset(BidirIt first, BidirIt last)
Resets to the not-ready (no-match) state over the sequence [first, last).
const value_type & suffix() const
The unmatched suffix (whole match end to sequence end).
const_iterator begin() const
difference_type length(size_type n=0) const
Length of group n (0 if out of range or unmatched).
const value_type & prefix() const
The unmatched prefix (sequence start up to the whole match).
value_type prefix_
Unmatched prefix.
bool ready() const noexcept
Whether a successful match has been stored.
A matched sub-expression: a [first, second) range into the searched sequence.
int compare(const string_type &other) const
Three-way length/lexicographic comparison against a string (std::sub_match::compare).
typename std::iterator_traits< BidirIt >::difference_type difference_type
Distance type.
BidirIt iterator
The underlying iterator.
bool matched
Whether this sub-expression participated.
string_type str() const
The matched text as an owned string (empty if it did not participate).
int compare(const sub_match &other) const
std::basic_string_view< value_type > view() const
A non-owning view of the matched text.
std::basic_string< value_type > string_type
The owning string type.
difference_type length() const
Length of the sub-match (0 if it did not participate).
typename std::iterator_traits< BidirIt >::value_type value_type
The character type.
BidirIt second
One past the end of the sub-match.
BidirIt first
Start of the sub-match.
std::regex_constants::match_flag_type to_std_match(regex_constants::match_flag_type f) noexcept
Maps compat match/format flags to std::regex_constants — exhaustive (the std path).
bool format_forces_std(std::string_view fmt) noexcept
Replacement format text that must route to std: $0. $0 is platform-variant (libstdc++ = the whole mat...
bool run_nocapture(BidirIt first, BidirIt last, const basic_regex< CharT, Traits > &re, bool anchored, regex_constants::match_flag_type mf)
Backend run without capturing (no match_results to fill).
void expand_format(std::string &out, const RealMatch &m, std::string_view fmt, std::string_view text, std::size_t prefix_start)
Appends one match's ECMAScript-expanded replacement.
bool replace_stays_real(regex_constants::match_flag_type f) noexcept
Whether regex_replace can run its substitution on real. The real expander honors only format_first_on...
bool run(BidirIt first, BidirIt last, match_results< BidirIt > &m, const basic_regex< CharT, Traits > &re, bool anchored, regex_constants::match_flag_type mf)
Runs the active backend over [first, last) and fills m. anchored selects whole-sequence match (regex_...
bool real_honors(regex_constants::match_flag_type mf) noexcept
Whether real can honor the requested match flags, so the operation may stay on it.
match_flag_type
Match-control flags: the common subset.
@ format_first_only
Replace only the first match.
@ format_no_copy
Do not copy the parts of the text that did not match.
bool regex_match(BidirIt first, BidirIt last, match_results< BidirIt > &m, const basic_regex< CharT, Traits > &re, regex_constants::match_flag_type flags=regex_constants::match_default)
Match of the entire [first, last) (Python re.fullmatch / std::regex_match).
bool regex_search(BidirIt first, BidirIt last, match_results< BidirIt > &m, const basic_regex< CharT, Traits > &re, regex_constants::match_flag_type flags=regex_constants::match_default)
Leftmost search of [first, last) (Python re.search / std::regex_search).
bool operator==(const sub_match< BidirIt > &lhs, const typename sub_match< BidirIt >::string_type &rhs)
Equality against an owned string (the common std::sub_match comparison).
std::basic_string< CharT > regex_replace(const std::basic_string< CharT > &s, const basic_regex< CharT, Traits > &re, const std::basic_string< CharT > &fmt, regex_constants::match_flag_type flags=regex_constants::format_default)
Replaces matches of re in s with the ECMAScript-formatted fmt.
constexpr std::size_t npos
Sentinel for "no position" / unset capture slot (akin to std::string::npos).
@ 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.
std::regex-compatibility layer, part 1/3: the constants, the error type, the backend-routing screens,...