1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package net.sf.statcvs.util;
24
25 import java.util.ArrayList;
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.StringTokenizer;
29 import java.util.regex.Pattern;
30
31 /**
32 * <p>Matches filenames against an Ant-style wildcard pattern list.</p>
33 *
34 * <p>In short, ? matches one character, * matches zero or more characters
35 * but no directory changes (it doesn't match / or \), and **
36 * matches zero or more directory levels. If the wildcard pattern
37 * ends in / or \, an implicit ** is added.</p>
38 *
39 * <p>Several patterns can be specified, seperated by : or ;.</p>
40 *
41 * <p>Everything is case sensitive. If you need case insensitive pattern
42 * matching, use <tt>String.toLower()</tt> on the pattern and on the
43 * candidate string.</p>
44 *
45 * @author Richard Cyganiak <rcyg@gmx.de>
46 * @version $Id: FilePatternMatcher.java,v 1.3 2008/04/02 11:22:15 benoitx Exp $
47 */
48 public class FilePatternMatcher {
49 private final String originalPattern;
50 private final List patterns = new ArrayList();
51
52 /**
53 * Creates a matcher to match filenames against a specified
54 * wildcard pattern
55 * @param wildcardPattern an Ant-style wildcard pattern
56 */
57 public FilePatternMatcher(final String wildcardPattern) {
58 this.originalPattern = wildcardPattern;
59 final StringTokenizer tokenizer = new StringTokenizer(wildcardPattern, ":;");
60 while (tokenizer.hasMoreTokens()) {
61 patterns.add(Pattern.compile(buildRegex(tokenizer.nextToken())));
62 }
63 }
64
65 /**
66 * Matches a filename against the wildcard pattern.
67 * @param filename a filename
68 * @return <tt>true</tt> if the filename matches the pattern
69 */
70 public boolean matches(final String filename) {
71 final Iterator it = patterns.iterator();
72 while (it.hasNext()) {
73 final Pattern regex = (Pattern) it.next();
74 if (regex.matcher(filename).matches()) {
75 return true;
76 }
77 }
78 return false;
79 }
80
81 private String buildRegex(final String wildcardPattern) {
82 String temp = wildcardPattern;
83 temp = temp.replace('\\', '/');
84 if (temp.endsWith("/")) {
85 temp += "**";
86 }
87 /** with **
88 temp = temp.replaceAll("\\*\\*/\\*\\*", "**");
89 if ("**".equals(temp)) {
90 return ".*";
91 }
92 // replace **/ at start with (.*/)? and /** at end with (/.*)?
93 if (temp.startsWith("**/") && temp.endsWith("/**")) {
94 final String inner = temp.substring(3, temp.length() - 3);
95 return "(.*/)?" + buildInnerRegex(inner) + "(/.*)?";
96 }
97 if (temp.startsWith("**/")) {
98 final String inner = temp.substring(3);
99 return "(.*/)?" + buildInnerRegex(inner);
100 }
101 if (temp.endsWith("/**")) {
102 final String inner = temp.substring(0, temp.length() - 3);
103 return buildInnerRegex(inner) + "(/.*)?";
104 }
105 return buildInnerRegex(temp);
106 }
107
108 private String buildInnerRegex(final String wildcardPattern) {
109 /**/ with /(.*/)?
110 final int pos = wildcardPattern.indexOf("/**/");
111 if (pos > -1) {
112 final String before = wildcardPattern.substring(0, pos);
113 final String after = wildcardPattern.substring(pos + 4);
114 return buildInnerRegex(before) + "/(.*/)?" + buildInnerRegex(after);
115 }
116
117 return wildcardPattern.replaceAll("\\?", "[^/]").replaceAll("\\*", "[^/]*");
118 }
119
120 public String toString() {
121 return this.originalPattern;
122 }
123 }