/* * Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * * Neither the name of Business Objects nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * WildcardPatternMatcher.java * Creation date: Sep 15, 2005. * By: Edward Lam */ package org.openquark.util; import java.util.regex.Pattern; /** * This class allows strings to matched against simple dos-style wildcard patterns. * In these patterns, "*" represents zero or more allowable characters, and "?" represents exactly one such character. * * @author Edward Lam */ public final class WildcardPatternMatcher { /** * Get the regex pattern corresponding to the provided pattern string. * @param patternString the pattern string. * @return the corresponding regex pattern, where "*" represents zero or more allowable characters, * and "?" represents exactly one such character. Null if the pattern string is zero length. */ public static Pattern getPattern(String patternString) { String regExpr = wildcardPatternToRegExp(patternString); return (regExpr.length() == 0) ? null : Pattern.compile(regExpr); } /** * Convert the wildcard pattern into a regular expression. * @param patternString the wildcard pattern. * @return the corresponding regular expression. */ public static String wildcardPatternToRegExp(String patternString) { // Ensure the pattern is simplified. patternString = simplifyPattern(patternString); // Convert a file name pattern (using * for multiple chars and ? for a single char) to a regular expression. String regExpr = patternString.trim(); // Replace any '\' chars with '\\'. regExpr = regExpr.replaceAll("\\\\", "\\\\\\\\"); // Replace any '.' chars with '\.'. regExpr = regExpr.replaceAll("\\.", "\\\\."); // Replace any '?' chars with '.'. regExpr = regExpr.replaceAll("\\?", "."); // Replace any '*' chars with '.*'. regExpr = regExpr.replaceAll("\\*", ".*"); // Replace any [, ], {, }, (, ), ^, $, +, | chars with the \ prefixed version. regExpr = regExpr.replaceAll("\\[", "\\\\["); regExpr = regExpr.replaceAll("\\]", "\\\\]"); regExpr = regExpr.replaceAll("\\{", "\\\\{"); regExpr = regExpr.replaceAll("\\}", "\\\\}"); regExpr = regExpr.replaceAll("\\(", "\\\\("); regExpr = regExpr.replaceAll("\\)", "\\\\)"); regExpr = regExpr.replaceAll("\\^", "\\\\^"); regExpr = regExpr.replaceAll("\\$", "\\\\$"); regExpr = regExpr.replaceAll("\\+", "\\\\+"); regExpr = regExpr.replaceAll("\\|", "\\\\|"); return regExpr; } /** * Match a string against a pattern. * @param stringToMatch the string to match. * @param patternString the string form of the pattern against which to match the string. * @return whether the string matches the pattern. */ public static boolean match(String stringToMatch, String patternString) { // Ensure the pattern is simplified. patternString = simplifyPattern(patternString); Pattern pattern = getPattern(patternString); if (pattern == null) { return stringToMatch.length() == 0; } return pattern.matcher(stringToMatch).matches(); } /** * Simplify a pattern * Any mix of "?" and one or more "*" is converted to the same number of ?, followed by a single "*". * * For example: foo***?**??*?bar * is converted to: foo????*bar * * @param pattern the pattern to simplify. * @return the simplified equivalent of the provided pattern. */ private static String simplifyPattern(String pattern) { if (pattern.indexOf("*?") < 0 && pattern.indexOf("**") < 0) { return pattern; } int patternLen = pattern.length(); char[] newPatternChars = new char[patternLen]; // Whether we are in a run of wildcards beginning with a "*". boolean inStarWildCardRun = false; // If we are in a run of wildcards beginning with a "*", the number of "?" in the run. int starWildCardQuestionCount = 0; // The number of chars in the new pattern. int newPatternCharCount = 0; for (int i = 0; i < patternLen; i++) { char patternChar = pattern.charAt(i); if (patternChar == '*') { inStarWildCardRun = true; } else if (patternChar == '?') { if (inStarWildCardRun) { starWildCardQuestionCount++; } else { newPatternChars[newPatternCharCount] = patternChar; newPatternCharCount++; } } else { // Not a wildcard. // If this is the first non-wildcard after a run of wildcards beginning with a "*", add the simplified run. if (inStarWildCardRun) { // Add the correct number of "?". for (int j = 0; j < starWildCardQuestionCount; j++) { newPatternChars[newPatternCharCount] = '?'; newPatternCharCount++; } // Add a single "*" newPatternChars[newPatternCharCount] = '*'; newPatternCharCount++; // Reset the wildcard trackers. inStarWildCardRun = false; starWildCardQuestionCount = 0; } newPatternChars[newPatternCharCount] = patternChar; newPatternCharCount++; } } // If the pattern ends with a run of wildcards beginning with a "*", add the simplified run. if (inStarWildCardRun) { // Add the correct number of "?". for (int j = 0; j < starWildCardQuestionCount; j++) { newPatternChars[newPatternCharCount] = '?'; newPatternCharCount++; } // Add a single "*" newPatternChars[newPatternCharCount] = '*'; newPatternCharCount++; } return new String(newPatternChars, 0, newPatternCharCount); } }