Reputation: 326
I have a text field where a user is required to input information.
JTextField data = new JTextField();
I have a requirment that if a user enters in *. Then it should be treated as a regex wildcard for when I search for the data.
I am looping through a series of files and reading each line one by one.
for(int i = 0; i < files.length; i++) {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(files[i]));
String text = null;
while ((text = reader.readLine()) != null) {
if(text.contains(data) return text; // Line that requires wildcard check
}
} catch(IOException e) {
e.printStackTrace();
} finally{
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {}
}
}
How could I achieve this wildcard check? I require to make the '*' become any character once entered by user.
Upvotes: 0
Views: 1440
Reputation: 44404
The problem is that the search string may contain other characters which would be significant in a regular expression, so it isn’t safe to just blindly convert *
to .*
.
You’ll want to use Pattern.quote on all parts of the search string except for the asterisks:
String[] parts = data.split("\\*");
Pattern pattern = Pattern.compile(
Stream.of(parts).map(Pattern::quote).collect(Collectors.joining(".*")));
if (pattern.matcher(text).find()) {
return text;
}
Breaking down the above statement:
data.split("\\*")
splits the string by a regular expression that literally matches the *
character, into an array of substrings. Examples:
"ab*cd"
→ { "ab", "cd" }
"1*2345*67"
→ { "1", "2345", "67" }
Stream.of(parts)
creates a Stream from the array of substrings.map(Pattern:quote)
replaces each element in the Stream with its quoted equivalent, so any regex metacharacters (other than *
) will be treated as ordinary characters. Thus, "1+1"
in the original user input would actually match those three characters in the searched files.collect(Collectors.joining(".*"))
reassembles the elements in the stream into a single String, with .*
between each quoted part.On a side note, you can avoid writing a finally
block by placing your BufferedReader in a try-with-resources statement:
String[] parts = data.split("\\*");
Pattern pattern = Pattern.compile(
Stream.of(parts).map(Pattern::quote).collect(Collectors.joining(".*")));
Matcher matcher = pattern.matcher("");
for (File file : files) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String text;
while ((text = reader.readLine()) != null) {
if (matcher.reset(text).find()) {
return text;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Because BufferedReader implements AutoCloseable, an implicit finally
block will be created which essentially does what you were doing: try to close the BufferedReader while suppressing any exception that might arise from the close attempt.
Upvotes: 1