2009-09-10 13 views
22

Używam OpenMCL na Darwin, i chciałbym zrobić coś takiego:Jak wykonać iterację w katalogu w Common Lisp?

(loop for f in (directory "somedir") 
    collect (some-per-file-processing f)) 

Ale nie mogę dostać directory powrócić coś innego niż NIL, a ja nie potrafię znaleźć żadnego dobre objaśnienie online (inne niż "różni się dla każdego systemu").

Jakieś wskazówki?

Odpowiedz

16

Czy Twoja specyfikacja ścieżki zawiera symbol wieloznaczny? Common Lisp jest ścieżka rzeczy jest dość trudny do uchwycenia na początku - przynajmniej dla mnie było ... Jak CLHS państw na directory funkcję:

Jeśli pathspec nie jest dziki, uzyskany lista będzie zawierać zarówno zero lub jeden element.

Aby mieć swoją ścieżkę zawierać symbol wieloznaczny, można wypróbować funkcję make-ścieżki dostępu, jak

(directory (make-pathname :directory '(:absolute "srv" "hunchentoot") :name :wild :type "lisp")) 

lub nawet

(directory (make-pathname :directory '(:absolute "srv" "hunchentoot") :name :wild :type :wild)) 

Znalazłem bibliotekę CL-FAD wielka pomoc do obsługi ścieżek i systemu plików. W szczególności jego funkcja list-directory może być łatwiejsza w użyciu niż zwykła standardowa funkcja directory.

+2

Tak pracował dla mnie - (katalog "ścieżka") powrócił zerowa, gdzie (katalog "pathname /*.*") dało mi oczekiwane rezultaty. – Justicle

+1

Potrzebujesz tylko plików z nazwami zawierającymi kropkę? – Svante

+0

Dziwne, huh? Właściwie to po plikach .h i .cpp, ale "pathname/*" zwraca NIL. – Justicle

26

Istnieją dwa sposoby określania ścieżek:

  • pomocą ciągów

Struny są oczywiście w zależności od platformy: Unix składnia vs. składni Windows dla przykładu.

"/Users/foo/bar.text" is a valid pathname 
"/Users/foo/*/foo.*" is a valid pathname with two wildcards 

Można utworzyć obiekt ścieżki dostępu z ciągiem:

? (pathname "/Users/bar/foo.text") 
#P"/Users/bar/foo.text" 

#p powyżej zapewnia, że ​​obiekt ścieżka (a nie łańcuch) jest tworzony, kiedy czytasz go z powrotem.

Wewnętrznie Common Lisp pracuje z obiektami ścieżek, ale pozwala używać normalnych ciągów znaków i tworzy obiekty ścieżek z nich, jeśli to konieczne.

Kiedy Common Lisp widzi ścieżkę, która nie zawiera wszystkich określonych składników (na przykład brakuje katalogu), to wypełnia komponenty z obiektu pathname, który jest wartością zmiennej * DEFAULT-PATHNAME-DEFAULTS *.

Dzięki funkcji DESCRIBE może obejrzysz składników ścieżki (tutaj Clozure CL):

? (describe (pathname "/Users/bar/*.text")) 
#P"/Users/bar/*.text" 
Type: PATHNAME 
Class: #<BUILT-IN-CLASS PATHNAME> 
TYPE: (PATHNAME . #<CCL::CLASS-WRAPPER PATHNAME #x3000401D03BD>) 
%PATHNAME-DIRECTORY: (:ABSOLUTE "Users" "bar") 
%PATHNAME-NAME: :WILD 
%PATHNAME-TYPE: "text" 
%PHYSICAL-PATHNAME-VERSION: :NEWEST 
%PHYSICAL-PATHNAME-DEVICE: NIL 
  • pomocą funkcji Lisp tworzenia ścieżka obiektów

make-PathName jest funkcją i wymaga kilku argumentów ze słowem kluczowym, aby określić składniki.

Czasami jest również przydatna, aby utworzyć nową ścieżkę w oparciu o już istniejącą:

(make-pathname :name "foo" :defaults (pathname "/Users/bar/baz.text")) 

Jeśli używasz DIRECTORY warto używać ścieżki z symboli wieloznacznych. DIRECTORY następnie zwróci listę pasujących nazw ścieżek. Nazwa "KATALOG" jest nieco myląca, ponieważ DIRECTORY nie wyświetla zawartości katalogu, ale podaje listę pasujących nazw ścieżek (zwykle) ścieżek zawierających symbole wieloznaczne. Symbole wieloznaczne mogą odpowiadać ciągom znaków w komponentach, takich jak /foo/s*c/list*.l*. "Istnieje również dzika karta **, która służy do dopasowywania części hierarchii katalogów takich jak/foo/** /test.lisp, który pasuje do wszystkich plików test.lisp pod foo katalogu i jego podkatalogów.

(directory "/Users/foo/Lisp/**/*.lisp") 

Przede powinna zwrócić listę wszystkich plików „LISP” w „/ Users/foo/Lisp /” i wszystko jego podkatalogów

Aby przywrócić .c plików w jednym katalogu użytku.

(directory "/Users/foo/c/src/*.c") 

pamiętać, że TRAGICZNA CTORY zwraca listę obiektów ścieżki (nie jest listą ciągów znaków).

? (directory (make-pathname 
       :name "md5" 
       :type :wild 
       :directory '(:absolute "Lisp" "cl-http" "cl-http-342" "server"))) 
(#P"/Lisp/cl-http/cl-http-342/server/md5.lisp" 
#P"/Lisp/cl-http/cl-http-342/server/md5.xfasl") 

Powyżej używa obiektu ścieżki, który został utworzony przez MAKE-PATHNAME. Zwraca wszystkie pliki pasujące do /Lisp/cl-http/cl-http-342/server/md5.*.

To jest taka sama, jak:

(directory "/Lisp/cl-http/cl-http-342/server/md5.*") 

która jest krótsza, ale zależy od składni nazw plików Unix.

+0

+1 Dobre podsumowanie ścieżek w LISP-ie, bardzo pomocne. – Justicle

8

Nowoczesna lista bibliotek Common Lisp wprowadzająca katalog to IOLIB.

To działa tak:

CL-USER> (iolib.os:list-directory "/etc/apt") 
(#/p/"trusted.gpg~" #/p/"secring.gpg" #/p/"trustdb.gpg" #/p/"sources.list" 
#/p/"sources.list~" #/p/"apt-file.conf" #/p/"apt.conf.d" #/p/"trusted.gpg" 
#/p/"sources.list.d") 

Należy zauważyć, że nie są wymagane ukośnik lub symbole wieloznaczne. Jest bardzo solidny i potrafi nawet przetwarzać nazwy plików z niepoprawnie zakodowanymi znakami Unicode.

różnice w porównaniu do CL-FAD:

  • Przedmiotem otrzymasz są IOLIB ścieżki plików, zastępuje ścieżek CL, która znajduje się bliżej co robi podstawowa OS.
  • IOLIB implementuje swoje procedury za pomocą CFFI, więc działa tak samo we wszystkich implementacjach Lisp (pod warunkiem, że IOLIB ma backend dla systemu operacyjnego), w przeciwieństwie do CL-FAD, który próbuje streścić funkcję DIRECTORY implementacji wraz z jej wszystkimi dziwactwa.
  • W przeciwieństwie do CL-FAD, iolib radzi sobie poprawnie z dowiązaniami symbolicznymi (jeden poważny problem z CL-FAD, który sprawia, że ​​praktycznie nie można go używać na platformach innych niż IMHO dla systemu Windows).
1

Dodam przykład, który działa dla mnie, ze względu na fragment kodu. Używam osicat (podobnego do cl-fad) i str.

edycja: również z uiop:directory-files. str: zawiera? można zrobić z search.

;; searching for "ref". 
(setf *data-directory* "~/books/lisp") 
(remove-if-not (lambda (it) 
        (str:contains? "ref" (namestring it))) 
       (osicat:list-directory *data-directory*)) 

powraca

(#P"~/books/lisp/common-lisp-quick-reference-clqr-a4-booklet-all.pdf" 
#P"~/books/lisp/common-lisp-quick-reference-clqr-a4-consec.pdf" 
#P"~/books/lisp/commonLisp-interactive-approach-reference-buffalo.pdf") 

To niewątpliwie można poprawić moją właściwego korzystania z symboli wieloznacznych. Jednak to fragment można użyć teraz:)

Referencje: