package org.theonefx.wcframework.utils;
/**
* This class provides a method for the programmar to test whether a f ile
* matches a wildcard.
*
* For he who is familiar with dos, he will probably refer to files us ing
* wildcard, that is file names like "*.bat","a?b.*",etc, this class gives you a
* method to test if they are match.
*
* A "*" can match any length of string including an empty string, A "?" can
* match any single char.
*
* So "abc" & "a*" matches "abc" & "*" matches "abc" & "b*" doesn"t match "abcd"
* & "a*d" matches "abcd" & "a??d" matches ......
*/
public class WildcardMatcher {
/**
* Tag to indicate if the strings should be compared case sensitive or not.
*/
private static boolean ignoreCase = false;
/**
* Empty construct, since all the methods are static, you don"t ha ve to
* make an object of this class, and thus I hide the construtor in private.
*/
private WildcardMatcher() {
}
/**
* Give the boolean value whether the given file name and the wild card
* matches.
*
* @param string
* The source string to be compared to the wildcard.
* @param wildcard
* The wildcard.
*
* @return True, if they matches.
*/
public static boolean match(String string, String wildcard) {
return match(string, wildcard, false);
}
/**
* Give the boolean value whether the given file name and the wild card
* matches.
*
* @param string
* The source string to be compared to the wildcard.
* @param wildcard
* The wildcard.
*
*
* @param ignorecase
* If this param is true, all the comparison is made not
* casesensitive.
*
* @return True, if they matches.
*/
public static boolean match(String string, String wildcard, boolean ignorecase) {
ignoreCase = ignorecase;
if (wildcard.indexOf("*") < 0)
return stringEquals(string, wildcard);
if (wildcard.equals("*"))
return true;
String sub = null;
int pw = 0, ps = 0, wlen = wildcard.length(), index;
boolean first = true;
while (pw < wlen) {
index = wildcard.indexOf("*", pw);
if (index < 0) {
sub = wildcard.substring(pw);
pw = wlen; // to skip out
} else {
sub = wildcard.substring(pw, index);
pw = index + 1;
}
index = find(string, sub, ps);
if (first) {
first = false;
if (index != 0) {
return false;
} else
ps = sub.length();
} else {
if (index < 0) {
return false;
}
ps = index + sub.length();
}
}
if (wildcard.charAt(wildcard.length() - 1) != '*') {
index = find(string, sub, string.length() - sub.length());
if (index < 0)
return false;
}
return true;
}
/**
* Inner method to test whether two string equals, it is same as S
* tring.equals, except that it supports wildcard "?"
*
* @param a
* A string to compare
* @param b
* A string to compare
*
* @return True If a and b equals, notice that this could be invol ve
* wildcard "?"
*/
private static boolean stringEquals(String a, String b) {
int alen = a.length(), blen = b.length();
if (alen != blen)
return false;
if (find(a, b, 0) == 0)
return true;
return false;
}
/**
* Find the match position of the two string, it is same as String .indexOf,
* except that it supports wildcard "?"
*
* @param string
* The source string to be compared to the pattern.
* @param pattern
* The wildcard contained string.
* @param startpos
* The start position of this search.
*
* @return The match position of the two string,-1 if they do not match.
*/
private static int find(String string, String pattern, int startpos) {
if (pattern.equals("")) {
return startpos;
}
int orgp, pp = 0, ps = startpos, strlen = string.length(), patternlen = pattern.length();
char pc, sc;
boolean cmatch;
orgp = ps;
while (ps < strlen) {
sc = string.charAt(ps);
pc = pattern.charAt(pp);
if (ignoreCase) {
cmatch = (charEqualsIgnoreCase(sc, pc) || pc == '?');
} else {
cmatch = (sc == pc || pc == '?');
}
if (!cmatch) {
pp = 0;
ps = ++orgp;
continue;
}
pp++;
ps++;
if (pp == patternlen) {
return orgp;
}
}
return -1;
}
/**
* Compare two char but ignore their case.
*
* @param a
* Char to compare.
* @param b
* Char to compare.
*
* @return True, if they equals or they equals while ignoring their case.
*/
private static boolean charEqualsIgnoreCase(char a, char b) {
if (a == b)
return true;
char t;
if (a > b) {
t = a;
a = b;
b = t;
} // now a<b
int at = getCharType(a);
int bt = getCharType(b);
if (at == UPPERCASE && bt == LOWERCASE && a + 'a' - 'A' == b)
return true;
return false;
}
/**
* This is a inner method called by charEqualsIgnoreCase, which gi ves the
* type of the cha.
*
* @param c
* The char to find type.
*
* @return LOWERCASE--if the char is in lowercase. UPPERCASE--if the char is
* in uppercase. NOT_A_LETTER--if the char is not a letter.
*/
private static int getCharType(char c) {
if (c >= 'a' && c <= 'z') {
return LOWERCASE;
}
if (c >= 'A' && c <= 'Z') {
return UPPERCASE;
}
return NOT_A_LETTER;
}
/**
* Constant value for char type that is in lowercase.
*/
final private static int LOWERCASE = 10;
/**
* Constant value for char type that is in uppercase.
*/
final private static int UPPERCASE = 20;
/**
* Constant value for char type that is not a letter.
*/
final private static int NOT_A_LETTER = 30;
public static void main(String[] args) {
String source = "jack aha love aha rose aha!";
String match = "Jack?aha*";
System.out.println(WildcardMatcher.match(source, match));
}
}