You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
2.8 KiB
130 lines
2.8 KiB
#include <iostream> |
|
#include <set> |
|
#include <string> |
|
#include <vector> |
|
|
|
bool CmpStrEx(const std::string& expr, const std::string& str) |
|
{ |
|
if(expr.empty() || str.empty()) return false; |
|
|
|
struct State |
|
{ |
|
struct Block |
|
{ |
|
const size_t b,len; |
|
const bool optional; |
|
Block(const size_t bb,const size_t ee,const bool o):b(bb),len(ee-bb),optional(o) {} |
|
}; |
|
|
|
struct Cursor |
|
{ |
|
size_t block,offset; |
|
bool operator <(const struct Cursor& c) const |
|
{ |
|
if(block<c.block) return true; |
|
if(block>c.block) return false; |
|
if(offset<c.offset) return true; |
|
return false; |
|
} |
|
}; |
|
|
|
typedef std::set<struct Cursor> Cursors; |
|
typedef std::set<struct Cursor>::iterator pCursor; |
|
|
|
std::vector<struct Block> blockchain; |
|
Cursors cursors; |
|
const std::string& s; |
|
|
|
Cursors InitCursors(size_t block) const |
|
{ |
|
Cursors cs; |
|
for(size_t i=block; i<blockchain.size(); ++i) |
|
{ |
|
cs.insert({i,0}); |
|
if(!blockchain[i].optional) break; |
|
} |
|
return cs; |
|
} |
|
|
|
State(const std::string& str):s(str) |
|
{ |
|
size_t cur=0; |
|
size_t bpos=0; |
|
|
|
// Parse blocks |
|
while(cur<s.length()) |
|
{ |
|
if('['==s[cur] || ']'==s[cur]) |
|
{ |
|
// Add current block to blockchain |
|
if(cur>bpos) blockchain.push_back(Block(bpos,cur,(']'==s[cur]))); |
|
cur++; |
|
bpos=cur; |
|
continue; |
|
} |
|
cur++; |
|
} |
|
// Add last block |
|
if(bpos<s.length()) blockchain.push_back(Block(bpos,s.length(),false)); |
|
|
|
// Creating cursors for the first symbol |
|
cursors=InitCursors(0); |
|
} |
|
|
|
bool CmpSmb(const char c) |
|
{ |
|
pCursor p=cursors.begin(); |
|
bool res=false; |
|
|
|
// Compare symbol with all cursors |
|
while(p!=cursors.end()) |
|
{ |
|
const Block& bl=blockchain[p->block]; |
|
if(c==s[bl.b+p->offset]) {res=true; ++p;} |
|
else p=cursors.erase(p); |
|
} |
|
|
|
// Increment cursors |
|
Cursors upd; // New cursors |
|
p=cursors.begin(); |
|
while(p!=cursors.end()) |
|
{ |
|
// Increment cursor on one position |
|
if(p->offset+1>=blockchain[p->block].len) // Go to next block |
|
{ |
|
Cursors cs=InitCursors(p->block+1); // Get cursors for next block |
|
p=cursors.erase(p); // Erase current cursor |
|
for(const auto& cur: cs) upd.insert(cur); // Copy cursors to new set |
|
continue; |
|
} |
|
else upd.insert({p->block,p->offset+1}); |
|
if(blockchain[p->block].optional) // If current block is optional next symbol may be from next block |
|
{ |
|
Cursors cs=InitCursors(p->block+1); // Get cursors for next blockchain |
|
for(const auto& cur: cs) upd.insert(cur); // Copy cursors to new set |
|
} |
|
++p; |
|
} |
|
|
|
cursors=upd; |
|
return res; |
|
} |
|
|
|
}; |
|
|
|
struct State st(expr); |
|
for(size_t pos=0; pos<str.length(); ++pos) |
|
{ |
|
if(!st.CmpSmb(str[pos])) return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
int main(int argc, char** argv) |
|
{ |
|
if(argc!=3) return 1; |
|
std::cout<<"Compare "<<argv[1]<<" with template "<<argv[2]<<": "<<(CmpStrEx(argv[2],argv[1])?"match":"not match")<<std::endl; |
|
return 0; |
|
}
|
|
|