2009-09-10 36 views
22

Tôi đang sử dụng OpenMCL trên Darwin, và tôi muốn làm điều gì đó như:Làm cách nào để lặp qua một thư mục trong Common Lisp?

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

Nhưng tôi không thể có được directory trở lại bất cứ điều gì khác hơn là NIL, và tôi dường như không thể tìm thấy bất kỳ giải thích tốt trực tuyến (khác với "khác nhau của nó cho mỗi hệ thống").

Mọi con trỏ?

Trả lời

16

Đặc tả tên đường dẫn của bạn có chứa ký tự đại diện không? thứ pathname Common Lisp là hơi khó để nắm bắt lúc đầu - ít nhất là đối với tôi nó là ... Khi CLHS bang trên directory chức năng:

Nếu pathspec không phải là hoang dã, các danh sách kết quả sẽ chứa một trong hai không hoặc một phần tử.

Để có tên đường dẫn của bạn bao gồm một ký tự đại diện, bạn có thể thử chức năng make-tên đường dẫn, như

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

Hoặc thậm chí

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

Tôi tìm thấy thư viện CL-FAD một trợ giúp lớn để xử lý tên đường dẫn và hệ thống tệp. Cụ thể, chức năng list-directory có thể dễ sử dụng hơn chức năng chuẩn directory.

+2

Yep làm việc cho tôi - (thư mục "tên đường dẫn") trở NIL, nơi (thư mục "pathname /*.*") đã cho tôi kết quả mong đợi. – Justicle

+1

Bạn chỉ cần các tệp có tên có dấu chấm? – Svante

+0

Lạ à? Tôi thực sự sau các tệp .h và .cpp, nhưng "pathname/*" trả về NIL. – Justicle

26

Về cơ bản có hai cách để xác định tên đường dẫn:

  • sử dụng chuỗi

Strings rõ ràng là phụ thuộc vào nền tảng này: cú pháp Unix và Windows cú pháp ví dụ.

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

Bạn có thể tạo một đối tượng tên đường dẫn từ một chuỗi:

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

CáC#p trên đảm bảo rằng một đối tượng tên đường dẫn (và không phải là một chuỗi) được tạo ra, khi bạn đọc nó trở lại.

? #P"/Users/bar/foo.text" 
#P"/Users/bar/foo.text" 

Vì vậy, nội bộ Lisp thường làm việc với các đối tượng đường dẫn, nhưng nó cho phép bạn sử dụng các chuỗi bình thường và tạo các đối tượng đường dẫn từ chúng nếu cần.

Khi Lisp thường thấy tên đường dẫn không có tất cả thành phần được chỉ định (ví dụ thư mục bị thiếu), thì nó sẽ điền vào các thành phần từ đối tượng đường dẫn là giá trị của variabel * DEFAULT-PATHNAME-DEFAULTS *.

Với chức năng MÔ TẢ bạn có thể nhìn vào các thành phần của một tên đường dẫn (ở đây 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 
  • sử dụng tên đường dẫn chức năng Lisp tạo các đối tượng

MAKE-TÊN_ĐƯỜNG_DẪN là hàm và phải mất một vài đối số từ khóa để chỉ định các thành phần.

Đôi khi nó cũng rất hữu ích để tạo ra một đường dẫn mới dựa trên hiện có:

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

Nếu bạn sử dụng MỤC nó rất hữu ích để sử dụng một tên đường dẫn với các kí hiệu. DIRECTORY sau đó sẽ trả về một danh sách các tên đường dẫn phù hợp. Tên 'DIRECTORY' hơi gây hiểu nhầm, vì DIRECTORY không liệt kê nội dung của một thư mục, nhưng liệt kê các tên đường dẫn phù hợp cho (thường) một tên đường dẫn với các ký tự đại diện. Các ký tự đại diện có thể khớp với chuỗi ký tự trong các thành phần như /foo/s*c/list*.l* ". Ngoài ra còn có thẻ hoang dã **, được sử dụng để khớp các phần của thư mục hierachy như/foo/** /test.lisp, mà phù hợp với tất cả các file test.lisp dưới foo thư mục và thư mục con của nó.

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

trên nên trả về một danh sách tất cả 'ngọng' tập tin trong '/ Users/foo/Lisp /' và tất cả thư mục con của nó

Để trả lại hồ sơ .c trong việc sử dụng thư mục duy nhất:.

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

Lưu ý rằng thảm khốc CTORY trả về một danh sách các đối tượng đường dẫn (không phải là danh sách các chuỗi).

? (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") 

Sử dụng trên một đối tượng đường dẫn được tạo bởi MAKE-PATHNAME. Nó trả về tất cả các tệp phù hợp với /Lisp/cl-http/cl-http-342/server/md5.*.

Đây là giống như:

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

đó là ngắn hơn, nhưng phụ thuộc vào cú pháp tên đường dẫn Unix.

+0

+1 Một bản tóm tắt tốt về tên đường dẫn trong LISP, rất hữu ích. – Justicle

8

Thư viện Common Lisp hiện đại đang triển khai danh sách thư mục là IOLIB.

Nó hoạt động như thế này:

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") 

Lưu ý rằng không có dấu gạch chéo hoặc ký tự đại diện được yêu cầu. Nó rất mạnh mẽ và thậm chí có thể xử lý tên tệp với các ký tự unicode được mã hóa không chính xác.

khác biệt so với CL-FAD:

  • Các đối tượng bạn nhận được IOLIB đường dẫn tập tin, một sự thay thế cho tên đường dẫn của CL được gần gũi hơn những gì hệ điều hành cơ bản thực hiện.IOLIB thực hiện các thói quen của nó bằng cách sử dụng CFFI, vì vậy nó hoạt động tương tự trên tất cả các triển khai Lisp (cung cấp IOLIB có một phụ trợ cho hệ điều hành), trái ngược với CL-FAD, cố gắng trừu tượng hóa chức năng DIRECTORY của thực hiện với tất cả quirks.
  • Ngược lại với CL-FAD, iolib xử lý chính xác với các liên kết tượng trưng (một vấn đề lớn với CL-FAD khiến nó hầu như không sử dụng được trên các nền tảng khác với Windows IMHO).
1

Tôi sẽ thêm ví dụ phù hợp với tôi, vì đoạn mã. Tôi sử dụng osicat (tương tự như cl-fad) và str.

chỉnh sửa: cũng với uiop:directory-files. str: chứa? có thể được thực hiện với search.

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

lợi nhuận

(#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") 

Nó chắc chắn có thể được cải thiện việc sử dụng đúng đắn của tôi về ký tự đại diện. Tuy nhiên đó là một đoạn mã, bạn có thể sử dụng ngay bây giờ:)

Tài liệu tham khảo:

Các vấn đề liên quan