Избежать части полного пути от регулярных выражений, сохранив при этом одну часть - PullRequest
1 голос
/ 06 мая 2019

Потребность

У меня есть архив папок, который выглядит так:

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.ci и v2.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 интерпретируется как Regex, что недопустимо в части pathname.toString().matches(setupsArchive + pattern).

Мои попытки заставить его работать под Windows

Я понял, что мне нужно экранировать часть setupsArchive моего выражения регулярного выражения и сохранить match() только с частью шаблона.

Поэтому я пытался:

1. Поместите архив настроек вокруг 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 Ответ

1 голос
/ 06 мая 2019

Вы можете использовать Pattern#asPredicate() в качестве фильтра для имен.

File#getName() вернет имя каталога (без полного пути).

Вы можете фильтровать файлы по типу (dir / file), а затем снова фильтровать результат, или вы можете преобразовать файл в имена и затем фильтровать.

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]
...