Java PathMatcher 在 Windows 上无法正常工作
Java PathMatcher not working properly on Windows
我尝试为我的 SimpleFileVisitor 实施 JUnit 测试,但使用的 PathMatcher 在 Windows 上无法正常工作。问题似乎是具有正则表达式模式的 PathMatcher 在 Linux 和 Windows:
上表现不同
import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
public class TestApp{
public static void main(String []args){
final PathMatcher glob = FileSystems.getDefault().getPathMatcher("glob:{/,/test}");
final PathMatcher regex = FileSystems.getDefault().getPathMatcher("regex:/|/test");
System.err.println(glob.matches(Paths.get("/"))); // --> Linux=true Windows=true
System.err.println(glob.matches(Paths.get("/test"))); // --> Linux=true Windows=true
System.err.println(glob.matches(Paths.get("/test2"))); // --> Linux=false Windows=false
System.err.println(regex.matches(Paths.get("/"))); // --> Linux=true Windows=false
System.err.println(regex.matches(Paths.get("/test"))); // --> Linux=true Windows=false
System.err.println(regex.matches(Paths.get("/test2"))); // --> Linux=false Windows=false
}
}
但是我的正则表达式中有一个更长的列表,用于多个文件,这些文件不容易迁移到 glob 语法。否则,如果我将每个模式都写为未分组模式,我会嵌套不允许的组或更长的列表。
以跨平台方式执行此操作的最佳方法是什么?
首先我想说这是 PathMatcher 的 glob 处理语法中未记录的行为。它似乎将反斜杠(在 Windows 文件系统上很常见)转换为正斜杠(或 vice-versa)。从而使其始终在 Linux 和 Windows.
之间工作
下一行演示了不同的输出:
System.out.println(Paths.get("/test")); // Will output '\test' on Windows, '/test' on Linux
为了解决最初的问题,我们需要使用一些 RegexFu。
FileSystems.getDefault().getPathMatcher("regex:/|/test");
需要成为
FileSystems.getDefault().getPathMatcher("regex:(/|\\)|((/|\\)test)");
- 第一组将检查
/
和 \
之间(您需要 \
来转义 \
,但是因为 Java 它需要输入 \\
).
- 第二组由两部分组成,第一部分再次检查
/
或 \
,第二部分是问题中输入的文本。
感谢@user3775041 提供了更清晰的正则表达式:
FileSystems.getDefault().getPathMatcher("regex:[/\\]|[/\\]test");
这已经在 Windows 10 和 Ubuntu 20.04 上进行了测试,两者都具有以下输出:
true
true
false
true
true
false
编辑:Java 中测试正则表达式模式的好网站是 https://www.regexplanet.com/advanced/java/index.html
如果您想要一个在 Linux 上代码为 运行 时正则表达式中不包含 Windows 文件分隔符的版本,您还可以使用:
String sep = Pattern.quote(File.separator);
PathMatcher regex = FileSystems.getDefault().getPathMatcher("regex:"+sep+"|"+sep+"test");
这会在 Linux/Windows 上打印相同的输出。
此代码适用于 window 和 linux:
String pattern = "regex:\./src/main/java/.*\.java|\./src/main/java/.*\.txt";
String newPattern;
if(File.separator.equals("\")) { //window fix
newPattern = pattern.replace("/", "\\");
}else { //linux
newPattern = pattern;
}
PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(newPattern);
我尝试为我的 SimpleFileVisitor 实施 JUnit 测试,但使用的 PathMatcher 在 Windows 上无法正常工作。问题似乎是具有正则表达式模式的 PathMatcher 在 Linux 和 Windows:
上表现不同import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
public class TestApp{
public static void main(String []args){
final PathMatcher glob = FileSystems.getDefault().getPathMatcher("glob:{/,/test}");
final PathMatcher regex = FileSystems.getDefault().getPathMatcher("regex:/|/test");
System.err.println(glob.matches(Paths.get("/"))); // --> Linux=true Windows=true
System.err.println(glob.matches(Paths.get("/test"))); // --> Linux=true Windows=true
System.err.println(glob.matches(Paths.get("/test2"))); // --> Linux=false Windows=false
System.err.println(regex.matches(Paths.get("/"))); // --> Linux=true Windows=false
System.err.println(regex.matches(Paths.get("/test"))); // --> Linux=true Windows=false
System.err.println(regex.matches(Paths.get("/test2"))); // --> Linux=false Windows=false
}
}
但是我的正则表达式中有一个更长的列表,用于多个文件,这些文件不容易迁移到 glob 语法。否则,如果我将每个模式都写为未分组模式,我会嵌套不允许的组或更长的列表。
以跨平台方式执行此操作的最佳方法是什么?
首先我想说这是 PathMatcher 的 glob 处理语法中未记录的行为。它似乎将反斜杠(在 Windows 文件系统上很常见)转换为正斜杠(或 vice-versa)。从而使其始终在 Linux 和 Windows.
之间工作下一行演示了不同的输出:
System.out.println(Paths.get("/test")); // Will output '\test' on Windows, '/test' on Linux
为了解决最初的问题,我们需要使用一些 RegexFu。
FileSystems.getDefault().getPathMatcher("regex:/|/test");
需要成为
FileSystems.getDefault().getPathMatcher("regex:(/|\\)|((/|\\)test)");
- 第一组将检查
/
和\
之间(您需要\
来转义\
,但是因为 Java 它需要输入\\
). - 第二组由两部分组成,第一部分再次检查
/
或\
,第二部分是问题中输入的文本。
感谢@user3775041 提供了更清晰的正则表达式:
FileSystems.getDefault().getPathMatcher("regex:[/\\]|[/\\]test");
这已经在 Windows 10 和 Ubuntu 20.04 上进行了测试,两者都具有以下输出:
true
true
false
true
true
false
编辑:Java 中测试正则表达式模式的好网站是 https://www.regexplanet.com/advanced/java/index.html
如果您想要一个在 Linux 上代码为 运行 时正则表达式中不包含 Windows 文件分隔符的版本,您还可以使用:
String sep = Pattern.quote(File.separator);
PathMatcher regex = FileSystems.getDefault().getPathMatcher("regex:"+sep+"|"+sep+"test");
这会在 Linux/Windows 上打印相同的输出。
此代码适用于 window 和 linux:
String pattern = "regex:\./src/main/java/.*\.java|\./src/main/java/.*\.txt";
String newPattern;
if(File.separator.equals("\")) { //window fix
newPattern = pattern.replace("/", "\\");
}else { //linux
newPattern = pattern;
}
PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher(newPattern);