Java PathMatcher 在 Windows 上无法正常工作

问题描述 投票:0回答:3

我尝试为我的 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 语法。否则,如果我将每个模式编写为非分组模式,我会嵌套不允许的组,或者甚至更长的列表。

以跨平台方式执行此操作的最佳方法是什么?

java regex path glob
3个回答
2
投票

首先我想说这是 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


1
投票

如果您想要一个在 Linux 上运行代码时在正则表达式中不包含 Windows 文件分隔符的版本,您还可以使用:

String sep = Pattern.quote(File.separator);
PathMatcher regex = FileSystems.getDefault().getPathMatcher("regex:"+sep+"|"+sep+"test");

这会在 Linux/Windows 上打印相同的输出。


1
投票

此代码适用于 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);
© www.soinside.com 2019 - 2024. All rights reserved.