Блок задач

3. Структуры данных

Темы
Сложность 4

Задача «Файловые маски»

Необходимо реализовать поиск файла / файлового пути по маске.

Маска содержит такие же символы, какие содержит путь / имя файла, а также может содержать два вида символов-джокеров: * и ?. Символ ? заменяет один любой символ, а * — любое количество символов.

Входные данные

Текстовый файл, содержащий в первой строке маску поиска, а в последующих строках набор имён файлов или файловых путей (в Windows такой набор путей можно получить, например, командой dir /B/S).

Например

*bit*.*
D:\OOP.2014\bmp
D:\OOP.2014\example.cpp
D:\OOP.2014\include
D:\OOP.2014\lib
D:\OOP.2014\src
D:\OOP.2014\vs2008
D:\OOP.2014\bmp\kitty-04-core.bmp
D:\OOP.2014\include\libbitmap.h
D:\OOP.2014\lib\libbitmapd.lib
D:\OOP.2014\src\libbitmap.cpp
D:\OOP.2014\vs2008\libbitmap.sln
D:\OOP.2014\vs2008\libbitmap.vcproj
D:\OOP.2014\vs2008\out.bmp
D:\OOP.2014\vs2008\test.vcproj

Задача

Необходимо разработать функцию, которая проверяет соответствие файлового пути заданной маске:

bool fnmatch(const std::string &mask, const std::string &filepath);

Маске file??.txt соответствуют файлы file00.txt, fileab.txt, а файлы 00.txt и fileabc.txt не соответствуют.

Маске a*b.* соответствуют файлы aab.doc, abvgdb.jpg, а файл aaa.aaa не соответствует.

Поскольку в строке пути в зависимости от контекста может в качестве разделителя использоваться как /, так и \, то следует предусмотреть "взаимозаменяемость" этих символов: маске a\b/c должны соответствовать строки a\b\c, a/b/c, a/b\c, и, конечно a\b/c.

Выходные данные

Текстовый файл с теми путями из входного списка, которые соответствуют маске.

В приведённом выше примере:

D:\OOP.2014\include\libbitmap.h
D:\OOP.2014\lib\libbitmapd.lib
D:\OOP.2014\src\libbitmap.cpp
D:\OOP.2014\vs2008\libbitmap.sln
D:\OOP.2014\vs2008\libbitmap.vcproj

Тестирование

Для основной функции fnmatch должен быть создан набор тестов, проверяющих корректность поиска на наборе примеров.

Возможное усложнение

Обработка полных путей к файлам (\path\to\file.txt). В этом случае символы * и ? действуют только внутри одного уровня иерархии (для указанного имени файла маска \path\*\*.txt сработает, а просто *.txt — нет).

Также добавляется ещё один тип символа-джокера — **. Он может заменить любое количество любых подкаталогов в пути файла. Например, **\*.txt будет включать в себя \rather\long\path\to\file.txt.