vChewing-macOS/Source/Engine/OpenVanilla/OVWildcard.h

249 lines
7.5 KiB
C++

//
// OVWildcard.h
//
// Copyright (c) 2007-2010 Lukhnos D. Liu
//
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
#ifndef OVWildcard_h
#define OVWildcard_h
#include <iostream>
#include <string>
#include <vector>
#include <cctype>
namespace OpenVanilla {
using namespace std;
class OVWildcard {
public:
OVWildcard(const string& expression, char matchOneChar = '?', char matchZeroOrMoreChar = '*', bool matchEndOfLine = true, bool caseSensitive = false)
: m_caseSensitive(caseSensitive)
, m_expression(expression)
, m_matchEndOfLine(matchEndOfLine)
, m_matchOneChar(matchOneChar)
, m_matchZeroOrMoreChar(matchZeroOrMoreChar)
{
size_t index;
for (index = 0; index < expression.length(); index++) {
if (expression[index] == matchOneChar || expression[index] == matchZeroOrMoreChar) break;
}
m_longestHeadMatchString = expression.substr(0, index);
for (string::size_type i = 0; i < expression.length(); i++) {
char c = expression[i];
if (c == matchOneChar) {
m_states.push_back(State(AnyOne, 0));
}
else if (c == matchZeroOrMoreChar) {
char nextChar = 0;
string::size_type j;
for (j = i + 1; j < expression.length(); j++) {
char k = expression[j];
if (k != matchZeroOrMoreChar) {
if (k == matchOneChar) k = -1;
nextChar = k;
break;
}
}
i = j;
m_states.push_back(State(AnyUntil, nextChar));
}
else {
m_states.push_back(State(Exact, c));
}
}
}
bool match(const string& target, size_t fromState = 0) const
{
string::size_type i = 0, slength = target.length();
vector<State>::size_type j, vlength = m_states.size();
for (j = fromState; j < vlength; j++) {
State state = m_states[j];
Directive d = state.first;
int k = state.second;
if (i >= slength) {
if (d == AnyUntil && !k) return true;
return false;
}
switch (d) {
case Exact:
if (!equalChars(target[i], k)) return false;
i++;
break;
case AnyOne:
i++;
break;
case AnyUntil:
if (k == -1) {
// means *?, equals ?, so just advance one character
i++;
}
else if (k == 0) {
// until end, always true
return true;
}
else {
bool found = false;
string::size_type backIndex;
for (backIndex = slength - 1; backIndex >= i; backIndex--) {
if (equalChars(target[backIndex], k)) {
string substring = target.substr(backIndex + 1, slength - (backIndex + 1));
if (match(substring, j + 1)) {
found = true;
i = backIndex + 1;
break;
}
}
if (!backIndex)
break;
}
if (!found)
return false;
}
break;
}
}
if (m_matchEndOfLine && i != slength)
return false;
return true;
}
const string longestHeadMatchString() const
{
return m_longestHeadMatchString;
}
const string expression() const
{
return m_expression;
}
bool isCaseSensitive() const
{
return m_caseSensitive;
}
char matchOneChar() const
{
return m_matchOneChar;
}
char matchZeroOrMoreChar() const
{
return m_matchZeroOrMoreChar;
}
friend ostream& operator<<(ostream& stream, const OVWildcard& wildcard);
protected:
enum Directive {
Exact,
AnyOne,
AnyUntil
};
typedef pair<Directive, int> State;
bool equalChars(char a, char b) const
{
if (m_caseSensitive)
return a == b;
else
return tolower(a) == tolower(b);
}
bool m_caseSensitive;
bool m_matchEndOfLine;
char m_matchOneChar;
char m_matchZeroOrMoreChar;
vector<State> m_states;
string m_expression;
string m_longestHeadMatchString;
public:
static const bool Match(const string& text, const string& expression, char matchOneChar = '?', char matchZeroOrMoreChar = '*', bool matchEndOfLine = true, bool caseSensitive = false)
{
OVWildcard exp(expression, matchOneChar, matchZeroOrMoreChar, matchEndOfLine, caseSensitive);
return exp.match(text);
}
static const vector<OVWildcard> WildcardsFromStrings(const vector<string>& expressions, char matchOneChar = '?', char matchZeroOrMoreChar = '*', bool matchEndOfLine = true, bool caseSensitive = false)
{
vector<OVWildcard> result;
vector<string>::const_iterator iter = expressions.begin();
for ( ; iter != expressions.end(); iter++)
result.push_back(OVWildcard(*iter, matchOneChar, matchZeroOrMoreChar, matchEndOfLine, caseSensitive));
return result;
}
static bool MultiWildcardMatchAny(const string& target, const vector<string>& expressions, char matchOneChar = '?', char matchZeroOrMoreChar = '*', bool matchEndOfLine = true, bool caseSensitive = false)
{
return MultiWildcardMatchAny(target, WildcardsFromStrings(expressions, matchOneChar, matchZeroOrMoreChar, matchEndOfLine, caseSensitive));
}
static bool MultiWildcardMatchAny(const string& target, const vector<OVWildcard>& expressions)
{
vector<OVWildcard>::const_iterator iter = expressions.begin();
for ( ; iter != expressions.end(); iter++) {
if ((*iter).match(target))
return true;
}
return false;
}
};
inline ostream& operator<<(ostream& stream, const OVWildcard& wildcard)
{
vector<OVWildcard::State>::size_type i, size = wildcard.m_states.size();
for (i = 0; i < size; i++) {
const OVWildcard::State& state = wildcard.m_states[i];
stream << "State " << i << ": " << state.first << ", " << state.second << endl;
}
return stream;
}
}
#endif