ALib C++ Framework
by
Library Version: 2605 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
wildcardmatcher.cpp
1namespace alib { namespace strings { namespace util {
2
3#define STRING -1
4#define ASTERISK -2
5
6template<typename TChar>
8 // Note: The following invariants will be true in the command vector:
9 // - A String-entry will be a non-empty string
10 // - No two * follow each other"
11 // - A ? will not follow an asterisk (combinations of ? and ' will be sorted to "?(n) *"
12
13 commands.clear();
14
15 TSubstring<TChar> parser= pattern;
16 while( parser.IsNotEmpty() ) {
17 // *
18 if(parser.CharAtStart() == '*' ) {
19 // add if empty or last is not * already.
20 if( commands.size() == 0
21 || commands.back().first != ASTERISK ) commands.emplace_back( ASTERISK, nullptr );
22
23 parser.ConsumeChar();
24 continue;
25 }
26
27 // ?
28 int qtyQ= 0;
29 while( parser.ConsumeChar('?') )
30 ++qtyQ;
31
32 if( qtyQ ) {
33 // previous is "*" ?
34 if( commands.size() > 1
35 && (commands.end()-1)->first == ASTERISK )
36 {
37
38 // before * we already have Q? -> add to the Q
39 if( commands.size() >= 2
40 && (commands.end()-2)->first > 0 )
41 {
42 (commands.end()-2)->first+= qtyQ;
43 continue;
44 }
45
46 commands.emplace( commands.end() - 1, qtyQ, nullptr );
47 continue;
48 }
49
50 // Just add it
51 commands.emplace_back( qtyQ, nullptr );
52 continue;
53 }
54
55 // strings
56 integer idx= 1;
57 while ( idx < parser.Length() && parser[idx] != '*' && parser[idx] != '?' )
58 ++idx;
59
60 commands.emplace_back( STRING, TString<TChar>(parser.Buffer(), idx ) );
61 parser.ConsumeChars( idx );
62 continue;
63 }
64
65}
66
67template<typename TChar>
68bool TWildcardMatcher<TChar>::Match( const TString<TChar>& pHaystack, lang::Case sensitivity ) {
69 if( commands.size() == 0 )
70 return true;
71
72 if( pHaystack.IsNull() )
73 return false;
74
75 TSubstring<TChar> haystack= pHaystack;
76 size_t actCmd = 0;
77 size_t lastCmd= size_t( commands.size() - 1 );
78 bool lastWasAsterisk= false;
79
80 for( actCmd= 0; actCmd <= lastCmd ; ++actCmd ) {
81 auto& cmd= commands[actCmd];
82
83 // ?
84 if( cmd.first > 0 ) {
85 if ( haystack.Length() < cmd.first )
86 return false;
87 haystack.template ConsumeChars<NC>( cmd.first );
88 continue;
89 }
90
91 // *
92 if( cmd.first == ASTERISK ) {
93 if ( actCmd == lastCmd )
94 return true;
95
96 lastWasAsterisk= true;
97 continue;
98 }
99
100 // string
101 if( cmd.second.Length() > haystack.Length() )
102 return false;
103
104 if( lastWasAsterisk ) {
105 integer idx= sensitivity==lang::Case::Sensitive ? haystack.template IndexOf<NC, lang::Case::Sensitive>( cmd.second, 0, haystack.Length() - cmd.second.Length() + 1 )
106 : haystack.template IndexOf<NC, lang::Case::Ignore >( cmd.second, 0, haystack.Length() - cmd.second.Length() + 1 );
107 if( idx < 0 )
108 return false;
109 haystack.ConsumeChars( idx + cmd.second.Length() );
110 lastWasAsterisk= false;
111 continue;
112 }
113
114 if( sensitivity==lang::Case::Sensitive ? (!haystack.template StartsWith<NC, lang::Case::Sensitive>( cmd.second ) )
115 : (!haystack.template StartsWith<NC, lang::Case::Ignore >( cmd.second ) ) )
116 return false;
117
118 haystack.template ConsumeChars<NC>( cmd.second.Length() );
119 }
120
121 return haystack.IsEmpty() || lastWasAsterisk;
122}
123
124template void TWildcardMatcher<nchar>::Compile( const TString<nchar>& pattern );
125template bool TWildcardMatcher<nchar>::Match ( const TString<nchar>& haystack, lang::Case sensitivity );
126template void TWildcardMatcher<wchar>::Compile( const TString<wchar>& pattern );
127template bool TWildcardMatcher<wchar>::Match ( const TString<wchar>& haystack, lang::Case sensitivity );
128
129#undef STRING
130#undef ASTERISK
131}}} // namespace [alib::strings::util]
constexpr integer Length() const
Definition string.hpp:300
constexpr bool IsEmpty() const
Definition string.hpp:349
TChar CharAtStart() const
Definition string.hpp:417
constexpr bool IsNotEmpty() const
Definition string.hpp:353
constexpr const TChar * Buffer() const
Definition string.hpp:295
constexpr bool IsNull() const
Definition string.hpp:334
integer ConsumeChars(integer regionLength, TSubstring *target=nullptr)
bool Match(const TString< TChar > &haystack, lang::Case sensitivity=lang::Case::Sensitive)
std::vector< std::pair< int, TString< TChar > > > commands
The result list of commands created with #".Compile" and executed with #".Match".
void Compile(const TString< TChar > &pattern)
Case
Denotes upper and lower case character treatment.
Definition alox.cpp:14
lang::integer integer
Type alias in namespace #"%alib".
Definition integers.hpp:149