#include <iostream>
#include <string>
typedef std::string::const_iterator It;
/*
* Extract sequences of non-wildcard characters from pattern range
*/
std::string extract_token(It &s, It e) // [s,e) is (sub)pattern
{
It wcard;
for (wcard=s; wcard!=e; ++wcard)
if ('?' == *wcard) break;
std::string token(s,wcard);
for (s=wcard; s!=e; ++s)
if ('?' != *s) break; // treat '??' as '?' in pattern
return token;
}
/*
* Match a (sub)pattern against a (sub)input
*
* Strategy:
* - extract first token from pattern
* - exit with success for no (more) tokens
* - for each token match in input
* - match the remainder of the pattern against the remainder of the
* input
* - if no successful submatch, fail, otherwise done
*
* There is recursion (the matching of the remainder class match(....)
* recursively).
*
* There is backtracking (if the recursive match doesn't succeed, we try the
* next token submatch)
*/
bool match(It patb, It pate, const std::string& input)
{
while (patb != pate)
{
// get next token from pattern, advancing patb
std::string token = extract_token(patb, pate); // updates patb
if (!token.empty()) // could happen if pattern begins/ends with redundant '?'
{
size_t submatch = input.find(token); // first submatch please
while (std::string::npos != submatch) // while we have a submatch
{
if (match(patb, pate, input.substr(token.size())))
return true; // match completed successfully
// look for later potential submatches (*backtrack*)
submatch = input.find(token, submatch+1);
}
return false; // required token not found
}
}
return true; // no (remaining) pattern, always match
}
bool match(const std::string& pattern, const std::string& input)
{
// just relay to overload more suited for recursion
return match(pattern.begin(), pattern.end(), input);
}
//////////////////////
// TEST PROGRAM
void test(const std::string& pattern, const std::string& input)
{
std::cout << std::boolalpha;
std::cout << "match(\"" << pattern << "\", \"" << input << "\") => "
<< match(pattern, input) << std::endl;
}
int main()
{
// matches
test("?????", "");
test("?????", "?????");
test("", "");
test("", "glorious");
test("?r?o", "glorious");
test("some?words?exist", "some silly words should, most definitely, be existing");
test("some??words?exist?", "some silly words should, most definitely, be existing");
// failing matches
test("_", "");
test("_", "glorious");
test("_", "glorious");
test("glorious", "glo?ious");
test("?some??words?exist?", "bogus");
}
I2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8c3RyaW5nPgoKdHlwZWRlZiBzdGQ6OnN0cmluZzo6Y29uc3RfaXRlcmF0b3IgSXQ7CgovKgogKiBFeHRyYWN0IHNlcXVlbmNlcyBvZiBub24td2lsZGNhcmQgY2hhcmFjdGVycyBmcm9tIHBhdHRlcm4gcmFuZ2UKICovCnN0ZDo6c3RyaW5nIGV4dHJhY3RfdG9rZW4oSXQgJnMsIEl0IGUpIC8vIFtzLGUpIGlzIChzdWIpcGF0dGVybgp7CiAgICBJdCB3Y2FyZDsKICAgIGZvciAod2NhcmQ9czsgd2NhcmQhPWU7ICsrd2NhcmQpCiAgICAgICAgaWYgKCc/JyA9PSAqd2NhcmQpIGJyZWFrOwoKICAgIHN0ZDo6c3RyaW5nIHRva2VuKHMsd2NhcmQpOwoKICAgIGZvciAocz13Y2FyZDsgcyE9ZTsgKytzKQogICAgICAgIGlmICgnPycgIT0gKnMpIGJyZWFrOyAvLyB0cmVhdCAnPz8nIGFzICc/JyBpbiBwYXR0ZXJuCgogICAgcmV0dXJuIHRva2VuOwp9CgovKgogKiBNYXRjaCBhIChzdWIpcGF0dGVybiBhZ2FpbnN0IGEgKHN1YilpbnB1dAogKgogKiBTdHJhdGVneToKICogICAgLSBleHRyYWN0IGZpcnN0IHRva2VuIGZyb20gcGF0dGVybgogKiAgICAtIGV4aXQgd2l0aCBzdWNjZXNzIGZvciBubyAobW9yZSkgdG9rZW5zCiAqICAgIC0gZm9yIGVhY2ggdG9rZW4gbWF0Y2ggaW4gaW5wdXQKICogICAgICAgIC0gbWF0Y2ggdGhlIHJlbWFpbmRlciBvZiB0aGUgcGF0dGVybiBhZ2FpbnN0IHRoZSByZW1haW5kZXIgb2YgdGhlCiAqICAgICAgICAgIGlucHV0CiAqICAgICAgICAtIGlmIG5vIHN1Y2Nlc3NmdWwgc3VibWF0Y2gsIGZhaWwsIG90aGVyd2lzZSBkb25lCiAqCiAqIFRoZXJlIGlzIHJlY3Vyc2lvbiAodGhlIG1hdGNoaW5nIG9mIHRoZSByZW1haW5kZXIgY2xhc3MgbWF0Y2goLi4uLikKICogcmVjdXJzaXZlbHkpLgogKgogKiBUaGVyZSBpcyBiYWNrdHJhY2tpbmcgKGlmIHRoZSByZWN1cnNpdmUgbWF0Y2ggZG9lc24ndCBzdWNjZWVkLCB3ZSB0cnkgdGhlCiAqIG5leHQgdG9rZW4gc3VibWF0Y2gpCiAqLwpib29sIG1hdGNoKEl0IHBhdGIsIEl0IHBhdGUsIGNvbnN0IHN0ZDo6c3RyaW5nJiBpbnB1dCkKewogICAgd2hpbGUgKHBhdGIgIT0gcGF0ZSkKICAgIHsKICAgICAgICAvLyBnZXQgbmV4dCB0b2tlbiBmcm9tIHBhdHRlcm4sIGFkdmFuY2luZyBwYXRiCiAgICAgICAgc3RkOjpzdHJpbmcgdG9rZW4gPSBleHRyYWN0X3Rva2VuKHBhdGIsIHBhdGUpOyAvLyB1cGRhdGVzIHBhdGIKCiAgICAgICAgaWYgKCF0b2tlbi5lbXB0eSgpKSAvLyBjb3VsZCBoYXBwZW4gaWYgcGF0dGVybiBiZWdpbnMvZW5kcyB3aXRoIHJlZHVuZGFudCAnPycKICAgICAgICB7CiAgICAgICAgICAgIHNpemVfdCBzdWJtYXRjaCA9IGlucHV0LmZpbmQodG9rZW4pOyAgLy8gZmlyc3Qgc3VibWF0Y2ggcGxlYXNlCgogICAgICAgICAgICB3aGlsZSAoc3RkOjpzdHJpbmc6Om5wb3MgIT0gc3VibWF0Y2gpICAvLyB3aGlsZSB3ZSBoYXZlIGEgc3VibWF0Y2gKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgaWYgKG1hdGNoKHBhdGIsIHBhdGUsIGlucHV0LnN1YnN0cih0b2tlbi5zaXplKCkpKSkKICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTsgLy8gbWF0Y2ggY29tcGxldGVkIHN1Y2Nlc3NmdWxseQoKICAgICAgICAgICAgICAgIC8vIGxvb2sgZm9yIGxhdGVyIHBvdGVudGlhbCBzdWJtYXRjaGVzICgqYmFja3RyYWNrKikKICAgICAgICAgICAgICAgIHN1Ym1hdGNoID0gaW5wdXQuZmluZCh0b2tlbiwgc3VibWF0Y2grMSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgcmV0dXJuIGZhbHNlOyAvLyByZXF1aXJlZCB0b2tlbiBub3QgZm91bmQKICAgICAgICB9CiAgICB9CiAgICByZXR1cm4gdHJ1ZTsgLy8gbm8gKHJlbWFpbmluZykgcGF0dGVybiwgYWx3YXlzIG1hdGNoCn0KCmJvb2wgbWF0Y2goY29uc3Qgc3RkOjpzdHJpbmcmIHBhdHRlcm4sIGNvbnN0IHN0ZDo6c3RyaW5nJiBpbnB1dCkKewogICAgLy8ganVzdCByZWxheSB0byBvdmVybG9hZCBtb3JlIHN1aXRlZCBmb3IgcmVjdXJzaW9uCiAgICByZXR1cm4gbWF0Y2gocGF0dGVybi5iZWdpbigpLCBwYXR0ZXJuLmVuZCgpLCBpbnB1dCk7IAp9CgovLy8vLy8vLy8vLy8vLy8vLy8vLy8vCi8vIFRFU1QgUFJPR1JBTQoKdm9pZCB0ZXN0KGNvbnN0IHN0ZDo6c3RyaW5nJiBwYXR0ZXJuLCBjb25zdCBzdGQ6OnN0cmluZyYgaW5wdXQpCnsKICAgIHN0ZDo6Y291dCA8PCBzdGQ6OmJvb2xhbHBoYTsKICAgIHN0ZDo6Y291dCA8PCAibWF0Y2goXCIiIDw8IHBhdHRlcm4gPDwgIlwiLCBcIiIgPDwgaW5wdXQgPDwgIlwiKSA9PiAiIAogICAgICAgICAgICAgIDw8IG1hdGNoKHBhdHRlcm4sIGlucHV0KSA8PCBzdGQ6OmVuZGw7Cn0KCmludCBtYWluKCkKewogICAgLy8gbWF0Y2hlcwogICAgdGVzdCgiPz8/Pz8iLCAgICAgICAgICAgICAgICIiKTsKICAgIHRlc3QoIj8/Pz8/IiwgICAgICAgICAgICAgICAiPz8/Pz8iKTsKICAgIHRlc3QoIiIsICAgICAgICAgICAgICAgICAgICAiIik7CiAgICB0ZXN0KCIiLCAgICAgICAgICAgICAgICAgICAgImdsb3Jpb3VzIik7CiAgICB0ZXN0KCI/cj9vIiwgICAgICAgICAgICAgICAgImdsb3Jpb3VzIik7CiAgICB0ZXN0KCJzb21lP3dvcmRzP2V4aXN0IiwgICAgInNvbWUgc2lsbHkgd29yZHMgc2hvdWxkLCBtb3N0IGRlZmluaXRlbHksIGJlIGV4aXN0aW5nIik7CiAgICB0ZXN0KCJzb21lPz93b3Jkcz9leGlzdD8iLCAgInNvbWUgc2lsbHkgd29yZHMgc2hvdWxkLCBtb3N0IGRlZmluaXRlbHksIGJlIGV4aXN0aW5nIik7CgogICAgLy8gZmFpbGluZyBtYXRjaGVzCiAgICB0ZXN0KCJfIiwgICAgICAgICAgICAgICAgICAgIiIpOwogICAgdGVzdCgiXyIsICAgICAgICAgICAgICAgICAgICJnbG9yaW91cyIpOwogICAgdGVzdCgiXyIsICAgICAgICAgICAgICAgICAgICJnbG9yaW91cyIpOwogICAgdGVzdCgiZ2xvcmlvdXMiLCAgICAgICAgICAgICJnbG8/aW91cyIpOwogICAgdGVzdCgiP3NvbWU/P3dvcmRzP2V4aXN0PyIsICJib2d1cyIpOwp9Cg==
match("?????", "") => true
match("?????", "?????") => true
match("", "") => true
match("", "glorious") => true
match("?r?o", "glorious") => true
match("some?words?exist", "some silly words should, most definitely, be existing") => true
match("some??words?exist?", "some silly words should, most definitely, be existing") => true
match("_", "") => false
match("_", "glorious") => false
match("_", "glorious") => false
match("glorious", "glo?ious") => false
match("?some??words?exist?", "bogus") => false