Java 通配符替换
Java WildCard replacement
我有一个文本字段,要求用户输入信息。
JTextField data = new JTextField();
我有一个要求,如果用户输入 *。然后当我搜索数据时,它应该被视为正则表达式通配符。
我正在循环浏览一系列文件并逐行阅读。
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) {}
}
}
我怎样才能实现这个通配符检查?我要求让'*'成为用户输入后的任何字符。
问题在于搜索字符串可能包含其他在正则表达式中很重要的字符,因此盲目地将 *
转换为 .*
是不安全的。
您需要在搜索字符串的所有部分使用 Pattern.quote,星号除外:
String[] parts = data.split("\*");
Pattern pattern = Pattern.compile(
Stream.of(parts).map(Pattern::quote).collect(Collectors.joining(".*")));
if (pattern.matcher(text).find()) {
return text;
}
分解以上语句:
data.split("\*")
通过字面匹配 *
字符的正则表达式将字符串拆分为子字符串数组。例子:
"ab*cd"
→{ "ab", "cd" }
"1*2345*67"
→{ "1", "2345", "67" }
Stream.of(parts)
从子字符串数组创建一个 Stream。
map(Pattern:quote)
将 Stream 中的每个元素替换为其引用的等效元素,因此任何正则表达式元字符(*
除外)都将被视为普通字符。因此,原始用户输入中的 "1+1"
实际上会匹配搜索文件中的这三个字符。
collect(Collectors.joining(".*"))
将流中的元素重新组合成一个字符串,每个引用部分之间有 .*
。
附带说明一下,您可以通过将 BufferedReader 放在 try-with-resources statement:
中来避免编写 finally
块
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();
}
}
因为 BufferedReader 实现了 AutoCloseable, an implicit finally
block will be created which essentially does what you were doing: try to close the BufferedReader while suppressing 关闭尝试可能引起的任何异常。
我有一个文本字段,要求用户输入信息。
JTextField data = new JTextField();
我有一个要求,如果用户输入 *。然后当我搜索数据时,它应该被视为正则表达式通配符。
我正在循环浏览一系列文件并逐行阅读。
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) {}
}
}
我怎样才能实现这个通配符检查?我要求让'*'成为用户输入后的任何字符。
问题在于搜索字符串可能包含其他在正则表达式中很重要的字符,因此盲目地将 *
转换为 .*
是不安全的。
您需要在搜索字符串的所有部分使用 Pattern.quote,星号除外:
String[] parts = data.split("\*");
Pattern pattern = Pattern.compile(
Stream.of(parts).map(Pattern::quote).collect(Collectors.joining(".*")));
if (pattern.matcher(text).find()) {
return text;
}
分解以上语句:
data.split("\*")
通过字面匹配*
字符的正则表达式将字符串拆分为子字符串数组。例子:"ab*cd"
→{ "ab", "cd" }
"1*2345*67"
→{ "1", "2345", "67" }
Stream.of(parts)
从子字符串数组创建一个 Stream。map(Pattern:quote)
将 Stream 中的每个元素替换为其引用的等效元素,因此任何正则表达式元字符(*
除外)都将被视为普通字符。因此,原始用户输入中的"1+1"
实际上会匹配搜索文件中的这三个字符。collect(Collectors.joining(".*"))
将流中的元素重新组合成一个字符串,每个引用部分之间有.*
。
附带说明一下,您可以通过将 BufferedReader 放在 try-with-resources statement:
中来避免编写finally
块
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();
}
}
因为 BufferedReader 实现了 AutoCloseable, an implicit finally
block will be created which essentially does what you were doing: try to close the BufferedReader while suppressing 关闭尝试可能引起的任何异常。