我尝试为我的 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 文件系统上常见)转换为正斜杠(反之亦然)。从而使其始终在 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 上打印相同的输出。
此代码适用于 Windows 和 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);