WildcardMatch.java |
package ij.util; /** * This class allows for simple wildcard pattern matching. Possible * patterns allow to match single characters ('?') or any count of * characters ('*').<p> * Wildcard characters can be escaped (default: by an '\').<p> * This class always matches for the whole word.<p> * Examples: * <pre> * WildcardMatch wm = new WildcardMatch(); * System.out.println(wm.match("CfgOptions.class", "C*.class")); // true * System.out.println(wm.match("CfgOptions.class", "?gOpti*c?as?")); // false * System.out.println(wm.match("CfgOptions.class", "??gOpti*c?ass")); // true * System.out.println(wm.match("What's this?", "What*\\?")); // true * System.out.println(wm.match("What's this?", "What*?")); // true * System.out.println(wm.match("A \\ backslash", "*\\\\?back*")); // true * </pre> */ public class WildcardMatch { public WildcardMatch() { } public WildcardMatch(char singleChar, char multipleChars) { this.sc = singleChar; this.mc = multipleChars; } /** * Sets new characters to be used as wildcard characters, overriding the * the default of '?' for any single character match and '*' for any * amount of characters, including 0 characters. * @param singleChar The char used to match exactly ONE character. * @param multipleChars The char used to match any amount of characters * including o characters. */ public void setWildcardChars(char singleChar, char multipleChars) { this.sc = singleChar; this.mc = multipleChars; } /** * Sets the new character to be used as an escape character, overriding the * the default of '\'. * @param escapeChar The char used to match escape wildcard characters. */ public void setEscapeChar(char escapeChar) { this.ec = escapeChar; } /** * Returns the character used to specify exactly one character. * @return Wildcard character matching any single character. */ public char getSingleWildcardChar() { return sc; } /** * Returns the character used to specify any amount of characters. * @return Wildcard character matching any count of characters. */ public char getMultipleWildcardChar() { return mc; } /** * Returns the character used to escape the wildcard functionality of a * wildcard character. If two escape characters are used in sequence, they * mean the escape character itself. It defaults to '\'. * @return Escape character. */ public char getEscapeChar() { return ec; } /** * Makes pattern matching case insensitive. * @param caseSensitive false for case insensitivity. Default is case * sensitive match. */ public void setCaseSensitive(boolean caseSensitive) { this.caseSensitive = caseSensitive; } /** * Returns the current state of case sensitivity. * @return true for case sensitive pattern matching, false otherwise. */ public boolean getCaseSensitive() { return caseSensitive; } boolean preceededByMultipleChar = false; /** * Matches a string against a pattern with wildcards. Two wildcard types * are supported: single character match (defaults to '?') and ANY * character match ('*'), matching any count of characters including 0. * Wildcard characters may be escaped by an escape character, which * defaults to '\'. * @param s The string, in which the search should be performed. * @param pattern The search pattern string including wildcards. * @return true, if string 's' matches 'pattern'. */ public boolean match(String s, String pattern) { preceededByMultipleChar = false; isEscaped = false; if (!caseSensitive) { pattern = pattern.toLowerCase(); s = s.toLowerCase(); } int offset = 0; while (true) { String ps = getNextSubString(pattern); int len = ps.length(); pattern = pattern.substring(len + escCnt); if (len > 0 && isWildcard(ps.charAt(0)) && escCnt == 0) { offset = getWildcardOffset(ps.charAt(0)); if (isSingleWildcardChar(ps.charAt(0))) { s = s.substring(1); // This is not yet enough: If a '*' precedes '?', 's' might be SHORTER // than seen here, for this we need preceededByMultipleChar variable... } if (pattern.length() == 0) { return s.length() <= offset || preceededByMultipleChar; } } else { int idx = s.indexOf(ps); if (idx < 0 || (idx > offset && !preceededByMultipleChar)) { return false; } s = s.substring(idx + len); preceededByMultipleChar = false; } if (pattern.length() == 0) { return s.length() == 0; } } } private char sc = '?'; private char mc = '*'; private char ec = '\\'; // Escape character private boolean caseSensitive = true; private boolean isEscaped = false; private int escCnt = 0; private String getNextSubString(String pat) { escCnt = 0; if ("".equals(pat)) { return ""; } if (isWildcard(pat.charAt(0))) { // if '?' is preceeded by '*', we need special considerations: if (pat.length() > 1 && !isSingleWildcardChar(pat.charAt(0)) && isSingleWildcardChar(pat.charAt(1))) { preceededByMultipleChar = true; } return pat.substring(0, 1); } else { String s = ""; int i = 0; while (i < pat.length() && !isWildcard(pat.charAt(i), isEscaped)) { if (pat.charAt(i) == ec) { isEscaped = !isEscaped; if (!isEscaped) { s += pat.charAt(i); } escCnt++; } else if (isWildcard(pat.charAt(i))) { isEscaped = false; s += pat.charAt(i); } else { s += pat.charAt(i); } i++; } return s; } } private boolean isWildcard(char c, boolean isEsc) { return !isEsc && isWildcard(c); } private boolean isSingleWildcardChar(char c) { return c == sc; } private boolean isWildcard(char c) { return c == mc || c == sc; } private int getWildcardOffset(char c) { if (c == mc) { return Integer.MAX_VALUE; } return 0; } }