/* * Copyright 2011 William Bernardet * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.googlecode.japi.checker.utils; import java.io.File; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; /** * This class will convert a Ant pattern (containing **) into a regular expression. * It allows to run each matching independently. * * @author william.bernardet@gmail.com * */ public class AntPatternMatcher { private static Map<String, AntPatternMatcher> matchers = new HashMap<String, AntPatternMatcher>(); private boolean casesensitive = true; private String expression; private Pattern pattern; public AntPatternMatcher(String expression) { this.setExpression(expression); } public AntPatternMatcher(String expression, boolean casesensitive) { this.casesensitive = casesensitive; this.setExpression(expression); } public String getExpression() { return expression; } static public boolean matches(String expression, String path, boolean casesensitive) { if (matchers.containsKey(getKey(casesensitive, expression))) { return matchers.get(getKey(casesensitive, expression)).matches(path); } else { AntPatternMatcher matcher = new AntPatternMatcher(expression, casesensitive); matchers.put(matcher.toString(), matcher); return matcher.matches(path); } } static public boolean matches(String expression, String path) { return matches(expression, path, true); } /** * * @param expression */ public void setExpression(String expression) { this.expression = expression; int flags = 0; if (!casesensitive) { flags = Pattern.CASE_INSENSITIVE; } this.pattern = Pattern.compile(AntPatternMatcher.convertToRegexp(expression), flags); } /** * Get the expression as pattern. * @return */ public Pattern getPattern() { return pattern; } /** * Matches a path to the expression. * @param path the path to match. * @return true if the path matches the expression. */ public boolean matches(String path) { return matches(new File(path)); } /** * Matches a path to the expression. * @param path the path to match. * @return true if the path matches the expression. */ public boolean matches(File path) { return pattern.matcher(normalizePath(path.getPath())).matches(); } /** * Convert an Ant Pattern into a regular expression. * It supports the following patterns: * '**': matches zero or several subdirs. * '*': matches zero or several characters. * '?': matches one character. * @param expression * @return a string representing the expression as a regular expression. */ static public String convertToRegexp(String expression) { int i = 0; int n = expression.length(); String result = ""; expression = normalizePath(expression); while (i < n) { char c = expression.charAt(i++); if (c == '*') { // identifying a ** if (i < expression.length() && expression.charAt(i) == '*') { result = result + "(?:(?:^|" + File.separator.replace("\\", "\\\\") + ")[^" + File.separator.replace("\\", "\\\\") + "]+)*(?:^|" + File.separator.replace("\\", "\\\\") + "|$)"; i++; // skipping next \ or / if ((i < expression.length()) && (expression.charAt(i) == File.separatorChar)) { i++; } } else { result = result + "[^" + File.separator.replace("\\", "\\\\") + "]*"; } } else if (c == '?') { result = result + "[^" + File.separator.replace("\\", "\\\\") + "]"; } else if (c == '[') { int j = i; if (j < n && expression.charAt(j) == '!') { j++; } if (j < n && expression.charAt(j) == ']') { j++; } while (j < n && expression.charAt(j) != ']') { j++; } if (j >= n) { result = result + "\\["; } else { String stuff = expression.substring(i, j).replace("\\", "\\\\"); i = j + 1; if (stuff.charAt(0) == '!') { stuff = "^" + stuff.substring(1); } else if (stuff.charAt(0) == '^') { stuff = "\\" + stuff; } result = result + "[" + stuff + "]"; } } else { if (c == File.separatorChar && i + 2 <= expression.length() && expression.charAt(i) == '*' && expression.charAt(i + 1) == '*') { // pass } else { result = result + Pattern.quote("" + c); } } } return result + "$"; } static private String getKey(boolean casesensitive, String expression) { return "<" + casesensitive + "," + expression + ">"; } public String toString() { return getKey(casesensitive, expression); } private static String normalizePath(String path) { if ('/' == File.separatorChar) { return path.replace('\\', File.separatorChar); } else { return path.replace('/', File.separatorChar); } } }