3232Matchers<std::string>::set(const std::string &d, CondModifiers mods)
3333{
3434 _data = d;
35- if (mods & COND_NOCASE) {
36- _nocase = true ;
37- }
35+ _mods = mods;
3836
3937 if (_op == MATCH_REGULAR_EXPRESSION) {
40- if (!_reHelper.setRegexMatch (_data, _nocase )) {
38+ if (!_reHelper.setRegexMatch (_data, has_modifier (_mods, CondModifiers::MOD_NOCASE) )) {
4139 std::stringstream ss;
4240
4341 ss << _data;
@@ -50,28 +48,63 @@ Matchers<std::string>::set(const std::string &d, CondModifiers mods)
5048 }
5149}
5250
53- // Special case for strings, to allow for insensitive case comparisons for std::string matchers.
5451template <>
5552bool
5653Matchers<std::string>::test_eq(const std::string &t) const
5754{
58- bool r = false ;
59-
60- if (_data.length () == t.length ()) {
61- if (_nocase) {
62- // ToDo: in C++20, this would be nicer with std::range, e.g.
63- // r = std::ranges::equal(_data, t, [](char c1, char c2) { return std::tolower(c1) == std::tolower(c2); });
64- r = std::equal (_data.begin (), _data.end (), t.begin (), [](char c1, char c2) {
65- return std::tolower (static_cast <unsigned char >(c1)) == std::tolower (static_cast <unsigned char >(c2));
66- });
67- } else {
68- r = (t == _data);
55+ std::string_view lhs = _data;
56+ std::string_view rhs = t;
57+ bool result = false ;
58+
59+ // ToDo: in C++20, we should be able to use std::ranges::equal, but this breaks on Ubuntu CI
60+ // return std::ranges::equal(a, b, [](char c1, char c2) {
61+ // return std::tolower(static_cast<unsigned char>(c1)) == std::tolower(static_cast<unsigned char>(c2));
62+ // });
63+ // Case-aware comparison
64+ auto compare = [&](const std::string_view a, const std::string_view b) -> bool {
65+ if (has_modifier (_mods, CondModifiers::MOD_NOCASE)) {
66+ return a.size () == b.size () && std::equal (a.begin (), a.end (), b.begin (), [](char c1, char c2) {
67+ return std::tolower (static_cast <unsigned char >(c1)) == std::tolower (static_cast <unsigned char >(c2));
68+ });
69+ }
70+ return a == b;
71+ };
72+
73+ // Case-aware substring match
74+ auto contains = [&](const std::string_view haystack, const std::string_view &needle) -> bool {
75+ if (!has_modifier (_mods, CondModifiers::MOD_NOCASE)) {
76+ return haystack.find (needle) != std::string_view::npos;
77+ }
78+ auto it = std::search (haystack.begin (), haystack.end (), needle.begin (), needle.end (), [](char c1, char c2) {
79+ return std::tolower (static_cast <unsigned char >(c1)) == std::tolower (static_cast <unsigned char >(c2));
80+ });
81+ return it != haystack.end ();
82+ };
83+
84+ if (has_modifier (_mods, CondModifiers::MOD_EXT)) {
85+ auto dot = rhs.rfind (' .' );
86+ if (dot != std::string_view::npos && dot + 1 < rhs.size ()) {
87+ result = compare (rhs.substr (dot + 1 ), lhs);
88+ }
89+ } else if (has_modifier (_mods, CondModifiers::MOD_SUF)) {
90+ if (rhs.size () >= lhs.size ()) {
91+ result = compare (rhs.substr (rhs.size () - lhs.size ()), lhs);
92+ }
93+ } else if (has_modifier (_mods, CondModifiers::MOD_PRE)) {
94+ if (rhs.size () >= lhs.size ()) {
95+ result = compare (rhs.substr (0 , lhs.size ()), lhs);
96+ }
97+ } else if (has_modifier (_mods, CondModifiers::MOD_MID)) {
98+ result = contains (rhs, lhs);
99+ } else {
100+ if (rhs.size () == lhs.size ()) {
101+ result = compare (rhs, lhs);
69102 }
70103 }
71104
72105 if (pi_dbg_ctl.on ()) {
73- debug_helper (t, " == " , r );
106+ debug_helper (t, " == " , result );
74107 }
75108
76- return r ;
109+ return result ;
77110}
0 commit comments