Java与Python双星号glob模式匹配差异及Java适配方案问询
Glob模式跨语言匹配差异问题解答
测试目录结构
测试使用的标准目录结构如下:
Tests │─── HelloWorld.java │ └── ui │── HelloWorld.java │ └── feature1 │── HelloWorld.java
复现现象
使用如下Java代码执行glob路径匹配:
import java.nio.file.*; public class Test{ public static void main(String[] args) throws Exception { PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + "Tests/**/*.java"); Path base = Paths.get(".").toAbsolutePath(); Files.walk(base).forEach((path) -> { path = base.relativize(path); if (pathMatcher.matches(path)) { System.out.println(path); } }); } }
代码执行后仅匹配到2个文件:
Tests\ui\feature1\HelloWorld.java Tests\ui\HelloWorld.java
Tests根目录下的Tests/HelloWorld.java未被匹配。
使用相同模式在Python中执行匹配验证:
>>> import glob >>> glob.glob('Tests/**/*.java', recursive=True) ['Tests\\HelloWorld.java', 'Tests\\ui\\HelloWorld.java', 'Tests\\ui\\feature1\\HelloWorld.java']
Python可正确匹配全部3个.java文件。
1. 匹配结果差异的核心原因
差异来自两门语言对glob通配符**的实现规则不同:
- Java实现规则:Java NIO默认
PathMatcher的glob规则明确规定,仅当**作为模式的最后一个路径段时,才允许匹配零层目录;如果**位于模式中间(即后面还跟有其他路径段),必须匹配至少一层目录。示例中使用的模式Tests/**/*.java中,**后面还有*.java段,属于中间位置,因此要求Tests目录和目标java文件之间必须存在至少一级子目录,直接放在Tests根目录下的HelloWorld.java因为中间没有子目录层级,无法被匹配。 - Python实现规则:Python的
glob模块在开启recursive=True时,不对**的位置做限制,无论**在模式哪个位置,都可以匹配零层或多层目录,因此Tests/**/*.java可以直接命中Tests根目录下的java文件。
2. 不修改匹配模式的Java代码调整方案
核心思路是:在不改动Tests/**/*.java模式串的前提下,对传给匹配器的待匹配路径做无副作用的格式调整,给中间的**补一个可被匹配的合法路径段.(代表当前目录,属于文件系统认可的空目录占位,不会改变路径指向的实际文件),让所有Tests目录下的java文件都满足**至少匹配一个段的要求。
调整后的可运行代码如下:
import java.nio.file.*; public class Test{ public static void main(String[] args) throws Exception { PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + "Tests/**/*.java"); Path base = Paths.get(".").toAbsolutePath(); Path testDirPrefix = Paths.get("Tests"); Files.walk(base).forEach((path) -> { Path relativePath = base.relativize(path); // 跳过Tests目录外的无关路径 if (!relativePath.startsWith(testDirPrefix)) { return; } // 构造带.段的匹配专用路径,不改变原文件指向 Path matchPath = testDirPrefix.resolve(".").resolve(relativePath.subpath(1, relativePath.getNameCount())); if (pathMatcher.matches(matchPath)) { System.out.println(relativePath); } }); } }
运行以上代码可以正确匹配全部3个java文件,与Python执行结果一致。
内容的提问来源于stack exchange,提问作者Mikhail Bolotov
相关产品推荐
相关产品推荐

