Как правильно сопоставить имена файлов в подкаталогах?

В настоящее время я изучаю книгу " Real World Haskell", и в одном упражнении из этой книги читателю предлагается реализовать сопоставление имен файлов с использованием **, который так же, как *, но также просматривает все подкаталоги в файловой системе. Ниже приведен фрагмент моего кода с комментариями (в данный момент много дублирования), а далее вы можете найти дополнительную информацию о коде. Я думаю, что размещенного кода достаточно для решения проблемы, и нет необходимости перечислять всю программу здесь.

case splitFileName pat of
        ("", baseName) -> do -- just the file name passed
            curDir <- getCurrentDirectory
            if searchSubDirs baseName -- check if file name has `**` in it
              then do 
                  contents <- getDirectoryContents curDir
                  subDirs <- filterM doesDirectoryExist contents
                  let properSubDirs = filter (`notElem` [".", ".."]) subDirs
                  subDirsNames <- forM properSubDirs $ \dir -> do
                                      namesMatching (curDir </> dir </> baseName) -- call the function recursively on subdirectories
                  curDirNames <- listMatches curDir baseName -- list matches in the current directory
                  return (curDirNames ++ (concat subDirsNames)) -- concatenate results into a single list
              else listMatches curDir baseName
        (dirName, baseName) -> do // full path passed
            if searchSubDirs baseName
              then do
                  contents <- getDirectoryContents dirName
                  subDirs <- filterM doesDirectoryExist contents
                  let properSubDirs = filter (`notElem` [".", ".."]) subDirs
                  subDirsNames <- forM properSubDirs $ \dir -> do
                                      namesMatching (dirName </> dir </> baseName) -- call the function recursively on subdirectories
                  curDirNames <- listMatches dirName baseName -- list matches in the passed directory
                  return (curDirNames ++ (concat subDirsNames)) -- concatenate results into a single list

Дополнительная информация:

pat шаблон, который я ищу (например, *.txt или же C:\\A\[a-z].*).

splitFileName это функция, которая разделяет путь к файлу на путь к каталогу и имя файла. Первый элемент кортежа будет пустым, если мы укажем только имя файла в pat,

searchSubDirs возвращается True если имя файла имеет ** в этом.

listMatches возвращает список имен файлов, которые соответствуют шаблону в каталоге, подставляя ** за *,

namesMatching это имя функции, отрывок которой я разместил.

Почему это не работает?

Когда я передаю только имя файла, программа ищет его только в текущем каталоге и подкаталогах первого уровня. Когда я передаю полный путь, он ищет только в указанном каталоге. Это похоже на случай (dirName, baseName) неправильно рекурсивно Я уже некоторое время смотрю на код и не могу понять, в чем проблема.

Заметка

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

1 ответ

Решение

Вот проблема:

              contents <- getDirectoryContents dirName
              subDirs <- filterM doesDirectoryExist contents

getDirectoryContents возвращает только конечные имена каталогов, так что вы должны предварять dirName (вместе с /) к элементам contents перед звонком doesDirectoryExist,

Другие вопросы по тегам