从正则表达式中转义完整路径的一部分,同时保留其中的一部分

Posted

技术标签:

【中文标题】从正则表达式中转义完整路径的一部分,同时保留其中的一部分【英文标题】:Escape a part of the full path from regex while keeping one part of it 【发布时间】:2019-09-24 06:33:14 【问题描述】:

需要

我有一个如下所示的文件夹存档:

C:\Users\myUser\myArchive\.
├───v1.ci
│   └───Linux
│       ├───111-001
│       └───222-ci
├───v1.dev
│   └───Linux
│       ├───111-001
│       ├───222-001
│       └───333-001
├───v2.ci
│   └───Linux
│       ├───111-001
│       └───222-ci
├───v2.dev
│   └───Linux
│       ├───111-001
│       ├───222-001
│       └───333-001
└───v2.safe
    └───Linux
        ├───111-001
        └───222-ci

我想在 Java 中创建一个静态函数,给定一个存档路径(在本例中为位置 C:\Users\myUser\myArchive\)和一个模式,返回一个 List<String> 与所有与该模式匹配的文件夹。

例如,如果我要说 setupsArchive = C:\Users\myUser\myArchive\pattern = v*.ci,那么列表应该由 v1.civ2.ci(与此模式匹配的两个文件夹)组成。

注意:不需要递归。我只关心存档下方文件夹的名称,而不关心其中的内容。

代码工作,但仅适用于 Linux

此函数在 Unix 环境中运行时有效:

private static List<String> getVersionsMatchingPattern(String pattern, String setupsArchive) 
    File allVersions = new File(setupsArchive);
    FileFilter versionFilter = pathname -> pathname.isDirectory() && pathname.toString().matches(setupsArchive + pattern);
    File[] filteredVersions = allVersions.listFiles(versionFilter);
    List<String> matchedVersions = new ArrayList<>();
    for (File version : filteredVersions) 
        matchedVersions.add(version.getName());
    
    matchedVersions.sort(Collections.reverseOrder());
    return matchedVersions;

但是,当我在 Windows 上运行它时,它会在这一行引发异常:

FileFilter versionFilter = pathname -> pathname.isDirectory() && pathname.toString().matches(setupsArchive + pattern);

例外是java.util.regex.PatternSyntaxException: Illegal/unsupported escape sequence near index 3,它的发生是因为(与Unix不同)Windows中的路径分隔符是反斜杠\,当我发送C:\Users\...\u被解释为非法的正则表达式在pathname.toString().matches(setupsArchive + pattern) 部分。

我尝试让它在 Windows 下工作

我知道我需要转义正则表达式的setupsArchive 部分,并仅将match() 与模式部分一起保留。

因此我尝试过:

1。将 setupsArchive 放在 Pattern.quote() 周围:

FileFilter versionFilter = pathname -> pathname.isDirectory() && pathname.toString().matches(Pattern.quote(setupsArchive) + pattern);

2。仅将正则表达式匹配应用于分析文件夹的基本名称:

FileFilter versionFilter = pathname -> pathname.isDirectory() && pathname.getName().matches(pattern);

在这两种情况下,代码都可以正常编译和执行,但它不会过滤任何内容(即,即使有与模式匹配的数据,列表也会返回空)。

有人知道吗?

【问题讨论】:

问题 #1:*. 是一个 shell 模式,而不是一个正则表达式模式。我确定您不想编写转换器。 【参考方案1】:

您可以利用 Pattern#asPredicate() 作为名称过滤器。

File#getName() 将返回目录的名称(不包括完整路径)。

您可以按类型(目录/文件)过滤文件,然后再次过滤结果,或者您可以将文件转换为名称然后过滤。

final Pattern rx = Pattern.compile("AB"); // Matches names wich contain 'AB'

File baseDir = new File("C:\\Users\\myUser\\myArchive\\");
Predicate<String> nameMatcher = rx.asPredicate();

// this will result in a list of File
List<File> result = Arrays.stream(baseDir.listFiles())
    .filter(f->f.isDirectory())
    .filter(f->nameMatcher.test(f.getName()))
    .collect(Collectors.toList());

System.out.println(result); // [C:\Users\myUser\myArchive\ABC003PR, C:\Users\myUser\myArchive\TAB113]


// this will result in a list of String 
List<String> result2 = Arrays.stream(baseDir.listFiles())
        .filter(f->f.isDirectory())
        .map(File::getName)
        .filter(nameMatcher)
        .collect(Collectors.toList());
System.out.println(result2); // [ABC003PR, TAB113]

【讨论】:

谢谢,它在 Linux 和 Windows 下都运行良好,并且只需要对我现有的代码进行很少的修改!

以上是关于从正则表达式中转义完整路径的一部分,同时保留其中的一部分的主要内容,如果未能解决你的问题,请参考以下文章

在 MySQL 中转义用户输入正则表达式的最佳方法是啥?

需要在正则表达式中转义的所有特殊字符的列表

在正则表达式中转义特殊字符

如何在 oracle 中转义特殊的正则表达式字符?

你如何在 Freemarker 中转义正则表达式字符串

我必须在 Perl 预编译的正则表达式中转义哪些字符?