Java 正则表达式和 PathMatcher

Java Regex and PathMatcher

我正在 Java 中编写一个应用程序,它显示一个文件列表,其中文件名中的第一个单词与用户定义的字符串匹配,然后根据某些偏好删除或重新排列它们。我目前正处于寻找找到文件的好方法的阶段。使用 this Java Tutorial 我得到了这样的结果:

Path source = Paths.get(sourceText.getText());
Path dest = Paths.get(destText.getText());

System.out.println("Source:" + source.toString());
System.out.println("P/N: " + partNoText.getText());

String matchString = "glob:**" + partNoText.getText() + "*";

System.out.println("Matching: " + matchString);

fileFinder = new FileFinder(matchString);

try {
    Files.walkFileTree(source, fileFinder);
} catch (IOException e1) {
    e1.printStackTrace();
}
for (Path path : fileFinder.getResult()) {
    System.out.println("Moving: " + path.getFileName());
    Path target = Paths.get(dest.toString() + "\" + path.getFileName());

    try {
        Files.move(path, target, REPLACE_EXISTING);
    } catch (IOException e1) {
        e1.printStackTrace();
    }
}

其中 FileFinder 扩展了 SimpleFileVisitor 并具有此 visitFile 方法:

public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
    System.out.println(file.toString());
    System.out.println(fileMatcher.matches(file));
    if (fileMatcher.matches(file)) {
        result.add(file);
        return FileVisitResult.CONTINUE;
    }
    return FileVisitResult.CONTINUE;
}

我的问题是 glob 会拾取文件名包含部件号的任何文件。以任何方式。因此,如果我的文件名为“12345 RevA Really Big Part 2: Electric Bugaloo”,那么如果用户输入“1”或“123”或 "Bugaloo",该字符串将匹配。理想情况下,它只会在用户输入“12345”时匹配。

我尝试将我的 matchString 切换为 "regex: .*" + partNoText + "\b",它适用于我从 this other Java Tutorial 修改的正则表达式测试工具。我究竟做错了什么? PathMatcher 与常规 Matcher 的工作方式不同吗?

P.S。任何包含单词 "Text" 的变量,如 sourceTextpartNoText 都是 JTextFields。 Hopefull 这是代码中唯一从我剪下的内容中大部分不清楚的部分。

"Does PathMatcher work differently than a regular Matcher?"
是的。 PathMatcher 使用文件名 globbing[1],而 Matcher 使用 正则表达式.

What Is a Glob? in the tutorial you linked, and compare that with the documentation for java.util.regex.Pattern
Globbing 比正则表达式匹配更受限制。

如果您有严格遵守的严格文件命名约定,您可能可以使用 globbing(我收回我之前评论的最后一部分)。

假设您的文件被命名为
numeric part number - space - optional revision & space - description

也就是说,部件号的位数可以是可变的,但是部件号后面的 space 是必需的并且始终存在。

所以你的例子 "12345 RevA Really Big Part 2: Electric Bugaloo" 符合 partNum==12345, revision="RevA ", description="Really Big Part 2: Electric Bugaloo"

用户输入部件号 P/N: 123 作为变量 userPN,然后您将 glob 构造为
String glob = userPN + " *"; 导致 glob 等于 "123 *"
这将 匹配 12345,如您所愿,因为 3 之后的 space 将不匹配 4.

如果文件名中的部件号后不是一个必需的space,但后面是总是字母,无论是版本还是描述,您都可以将 glob 构造为
String glob = userPN + "[A-Z,a-z]*"; 给出 glob = 123[A-Z,a-z]* 也不会匹配 12345,因为字母必须跟在 123 之后,而 4 不在该字符范围内。

你可以让你的字符范围更复杂,比如 [A-Z,a-z, ] 一个 可选 space,这取决于你的需要,但是 这一切都归结为您的文件命名约定。您需要非常准确地说明该约定并遵守它。


[1] a PathMatcher 如果在调用 FileSystem.getPathMatcher(String)。这将类似于

FileSystem fs = FileSystems.getDefault();
PathMatcher pm = fs.getPathMatcher("regex:\d{5}\s.*");

我认为你走的路很复杂。当您不查找事件时,为什么首先要使用 pat Marc her。

遍历文件树并为每个目录迭代目录流以匹配您的 glob 会容易得多。