他人の空似自作物置場

touhouSE.zip/touhouSE_src/pattern.h


class Pattern {
protected:
   std::wstring normalizePath(const std::filesystem::path &path) const {
      std::wstring result = path.wstring();
      std::replace(result.begin(), result.end(), L'\\', L'/');
      return result;
   }
public:
   virtual bool match(const std::wstring &str) const = 0;
   virtual bool match(const std::filesystem::path &path) const {
      return match(normalizePath(path)) || match(path.filename().wstring());
   }
   virtual std::wstring toString() const = 0;
};

class RegexPattern : public Pattern {
private:
   const std::wregex pattern;
   const std::wstring patternStr;

public:
   RegexPattern(const std::wstring &pattern) : pattern(pattern), patternStr(pattern) {
   }
   virtual bool match(const std::wstring &str) const {
      return std::regex_search(str, pattern);
   }
   virtual std::wstring toString() const {
      return (boost::wformat(L"RegexPattern(%s)") % patternStr).str();
   }
};

class PlainPattern : public Pattern {
private:
   const std::wstring pattern;

public:
   PlainPattern(const std::wstring &pattern) : pattern(pattern) {
   }
   virtual bool match(const std::wstring &str) const {
      return str == pattern;
   }
   virtual std::wstring toString() const {
      return (boost::wformat(L"PlainPattern(%s)") % pattern).str();
   }
};

class GlobPattern : public Pattern {
private:
   const std::wstring pattern;

   static bool matchInner(std::wstring::const_iterator patternBegin, std::wstring::const_iterator patternEnd, std::wstring::const_iterator strBegin, std::wstring::const_iterator strEnd) {
      while (patternBegin != patternEnd && strBegin != strEnd) {
         if (*patternBegin == L'*') {
            patternBegin++;
            if (patternBegin == patternEnd) {
               return true;
            }
            for (; strBegin != strEnd; strBegin++) {
               if (matchInner(patternBegin, patternEnd, strBegin, strEnd)) {
                  return true;
               }
            }
            return false;
         }
         if (*patternBegin == L'?') {
            patternBegin++;
            strBegin++;
            continue;
         }
         if (*patternBegin == L'[') {
            patternBegin++;
            const std::wstring::const_iterator it = std::find(patternBegin, patternEnd, L']');
            if (it == patternEnd || std::distance(patternBegin, it) < 1) {
               return false;
            }
            const bool not = (*patternBegin == L'!');
            if (not) {
               patternBegin++;
            }
            if (std::distance(patternBegin, it) < 1) {
               return false;
            }
            if (*(patternBegin + 1) != L'-') { // [abc]
               const std::wstring::const_iterator findIt = std::find(patternBegin, it, *strBegin);
               if ((!not && findIt == it) || (not && findIt != it)) {
                  return false;
               }
            } else { // [a-z]
               if (std::distance(patternBegin, it) != 3) {
                  return false;
               }
               const wchar_t begin = *patternBegin;
               const wchar_t end = *(patternBegin + 2);
               if (begin >= end) {
                  return false;
               }
               if (
                  (!not && (*strBegin < begin || end < *strBegin))
                  || (not && begin <= *strBegin && *strBegin <= end)
               ) {
                  return false;
               }
            }
            patternBegin = it + 1;
            strBegin++;
            continue;
         }
         if (*patternBegin != *strBegin) {
            return false;
         }
         patternBegin++;
         strBegin++;
      }
      return patternBegin == patternEnd && strBegin == strEnd;
   }
public:
   GlobPattern(const std::wstring &pattern) : pattern(pattern) {
   }
   virtual bool match(const std::wstring &str) const {
      return matchInner(pattern.begin(), pattern.end(), str.begin(), str.end());
   }
   virtual std::wstring toString() const {
      return (boost::wformat(L"GlobPattern(%s)") % pattern).str();
   }
};