1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.io.filefilter;
18
19 import java.io.File;
20 import java.io.Serializable;
21 import java.nio.file.FileVisitResult;
22 import java.nio.file.Path;
23 import java.nio.file.attribute.BasicFileAttributes;
24 import java.util.Objects;
25 import java.util.function.Function;
26 import java.util.regex.Pattern;
27
28 import org.apache.commons.io.IOCase;
29 import org.apache.commons.io.file.PathUtils;
30
31 /**
32 * Filters files using supplied regular expression(s).
33 * <p>
34 * See java.util.regex.Pattern for regex matching rules.
35 * </p>
36 * <h2>Using Classic IO</h2>
37 * <p>
38 * e.g.
39 *
40 * <pre>
41 * File dir = FileUtils.current();
42 * FileFilter fileFilter = new RegexFileFilter("^.*[tT]est(-\\d+)?\\.java$");
43 * File[] files = dir.listFiles(fileFilter);
44 * for (String file : files) {
45 * System.out.println(file);
46 * }
47 * </pre>
48 *
49 * <h2>Using NIO</h2>
50 *
51 * <pre>
52 * final Path dir = PathUtils.current();
53 * final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.withLongCounters(new RegexFileFilter("^.*[tT]est(-\\d+)?\\.java$"));
54 * //
55 * // Walk one directory
56 * Files.<strong>walkFileTree</strong>(dir, Collections.emptySet(), 1, visitor);
57 * System.out.println(visitor.getPathCounters());
58 * System.out.println(visitor.getFileList());
59 * //
60 * visitor.getPathCounters().reset();
61 * //
62 * // Walk directory tree
63 * Files.<strong>walkFileTree</strong>(dir, visitor);
64 * System.out.println(visitor.getPathCounters());
65 * System.out.println(visitor.getDirList());
66 * System.out.println(visitor.getFileList());
67 * </pre>
68 * <h2>Deprecating Serialization</h2>
69 * <p>
70 * <em>Serialization is deprecated and will be removed in 3.0.</em>
71 * </p>
72 *
73 * @since 1.4
74 */
75 public class RegexFileFilter extends AbstractFileFilter implements Serializable {
76
77 private static final long serialVersionUID = 4269646126155225062L;
78
79 /**
80 * Compiles the given pattern source.
81 *
82 * @param pattern the source pattern.
83 * @param flags the compilation flags.
84 * @return a new Pattern.
85 */
86 private static Pattern compile(final String pattern, final int flags) {
87 Objects.requireNonNull(pattern, "pattern");
88 return Pattern.compile(pattern, flags);
89 }
90
91 /**
92 * Converts IOCase to Pattern compilation flags.
93 *
94 * @param ioCase case-sensitivity.
95 * @return Pattern compilation flags.
96 */
97 private static int toFlags(final IOCase ioCase) {
98 return IOCase.isCaseSensitive(ioCase) ? 0 : Pattern.CASE_INSENSITIVE;
99 }
100
101 /** The regular expression pattern that will be used to match file names. */
102 private final Pattern pattern;
103
104 /** How convert a path to a string. */
105 private final transient Function<Path, String> pathToString;
106
107 /**
108 * Constructs a new regular expression filter for a compiled regular expression
109 *
110 * @param pattern regular expression to match.
111 * @throws NullPointerException if the pattern is null.
112 */
113 @SuppressWarnings("unchecked")
114 public RegexFileFilter(final Pattern pattern) {
115 this(pattern, (Function<Path, String> & Serializable) PathUtils::getFileNameString);
116 }
117
118 /**
119 * Constructs a new regular expression filter for a compiled regular expression
120 *
121 * @param pattern regular expression to match.
122 * @param pathToString How convert a path to a string.
123 * @throws NullPointerException if the pattern is null.
124 * @since 2.10.0
125 */
126 public RegexFileFilter(final Pattern pattern, final Function<Path, String> pathToString) {
127 Objects.requireNonNull(pattern, "pattern");
128 this.pattern = pattern;
129 this.pathToString = pathToString != null ? pathToString : Objects::toString;
130 }
131
132 /**
133 * Constructs a new regular expression filter.
134 *
135 * @param pattern regular string expression to match
136 * @throws NullPointerException if the pattern is null
137 */
138 public RegexFileFilter(final String pattern) {
139 this(pattern, 0);
140 }
141
142 /**
143 * Constructs a new regular expression filter with the specified flags.
144 *
145 * @param pattern regular string expression to match
146 * @param flags pattern flags - e.g. {@link Pattern#CASE_INSENSITIVE}
147 * @throws IllegalArgumentException if the pattern is null
148 */
149 public RegexFileFilter(final String pattern, final int flags) {
150 this(compile(pattern, flags));
151 }
152
153 /**
154 * Constructs a new regular expression filter with the specified flags case sensitivity.
155 *
156 * @param pattern regular string expression to match
157 * @param ioCase how to handle case sensitivity, null means case-sensitive
158 * @throws IllegalArgumentException if the pattern is null
159 */
160 public RegexFileFilter(final String pattern, final IOCase ioCase) {
161 this(compile(pattern, toFlags(ioCase)));
162 }
163
164 /**
165 * Tests to see if the file name matches one of the regular expressions.
166 *
167 * @param dir the file directory (ignored)
168 * @param name the file name
169 * @return true if the file name matches one of the regular expressions
170 */
171 @Override
172 public boolean accept(final File dir, final String name) {
173 return pattern.matcher(name).matches();
174 }
175
176 /**
177 * Tests to see if the file name matches one of the regular expressions.
178 *
179 * @param path the path
180 * @param attributes the path's basic attributes (may be null).
181 * @return true if the file name matches one of the regular expressions
182 */
183 @Override
184 public FileVisitResult accept(final Path path, final BasicFileAttributes attributes) {
185 final String result = pathToString.apply(path);
186 return toFileVisitResult(result != null && pattern.matcher(result).matches());
187 }
188
189 /**
190 * Returns a debug string.
191 *
192 * @since 2.10.0
193 */
194 @Override
195 public String toString() {
196 return "RegexFileFilter [pattern=" + pattern + "]";
197 }
198
199 }