如何在Common Lisp中搜索带通配符的文件?

时间:2018-02-16 18:22:09

标签: common-lisp wildcard pathname

我不满意找到匹配字符串的文件:

(remove-if-not (lambda (it)
                   (search "wildcard" (namestring it)))
               (uiop:directory-files "./"))
;; I'll ignore case with str:contains?
;; https://github.com/vindarel/cl-str

如何使用unix样式的通配符搜索文件?

如果它不是内置的,我会享受uiop的解决方案。也许有Osicatcl-fad(它似乎并非如此,文档经常说"非野生路径名")。

如果可以使用双通配符递归遍历目录(./**/*.jpg),则获得奖励。

修改:我尝试了(directory #p"./**/*.jpg")的变体,它返回了nil :(也尝试了#p".*jpg"#p"./.*jpg",...

(wild-pathname-p (pathname "*.jpg"))
(:WILD :WILD-INFERIORS)


(make-pathname :name :wild :type "jpg")
#P"*.jpg"

以下通过jpg扩展程序获取文件,但它还不是一个合适的通配符:

(directory *)
(#P"/home/vince/cl-cookbook/AppendixA.jpg"
 #P"/home/vince/cl-cookbook/AppendixB.jpg"
 #P"/home/vince/cl-cookbook/AppendixC.jpg")

路径名和make-pathname的文档:http://gigamonkeys.com/book/files-and-file-io.html(未提及通配符)

2 个答案:

答案 0 :(得分:7)

SBCL

SBCL支持名称中的通配符。首先,创建一些文件:

{
  market_hash_name: price,
  market_hash_name: price.. etc
}

然后,列出包含“a”的所有文件:

Object.keys(data).length === 30000

路径名包含特定于实现的(有效)名称组件:

(loop 
  with stem = #P"/tmp/stack/_.txt"
  initially (ensure-directories-exist stem)
  for name in '("abc" "def" "cadar" "cdadr" "cddr")
  for path = (make-pathname :name name :defaults stem)
  do (open path :direction :probe :if-does-not-exist :create))

SBCL还定义了CL-USER> (directory #P"/tmp/stack/*a*.txt") (#P"/tmp/stack/abc.txt" #P"/tmp/stack/cadar.txt" #P"/tmp/stack/cdadr.txt") ,它逐个处理文件,而不是先收集列表中的所有文件。

便携式解决方案

如果您需要坚持使用标准路径名组件,可以先使用普通通配符调用CL-USER> (describe #P"/tmp/stack/*a*.txt") #P"/tmp/stack/*a*.txt" [structure-object] Slots with :INSTANCE allocation: HOST = #<SB-IMPL::UNIX-HOST {10000F3FF3}> DEVICE = NIL DIRECTORY = (:ABSOLUTE "tmp" "stack") NAME = #<SB-IMPL::PATTERN :MULTI-CHAR-WILD "a" :MULTI-CHAR-WILD> TYPE = "txt" VERSION = :NEWEST ; No value ,然后过滤生成的列表:

sb-ext:map-directory

...其中directory可能基于正则表达式(PPCRE):

CL-USER> (remove-if-not (wildcard "*a*")
                        (directory #P"/tmp/stack/*.txt")
                        :key #'pathname-name)

(#P"/tmp/stack/abc.txt" #P"/tmp/stack/cadar.txt" #P"/tmp/stack/cdadr.txt")

(注意:上面的负面反馈会消除转义的反斜杠)

wildcard

中级职能:

(defun parse-wildcard (string)
  (delete ""
          (map 'list
               (lambda (string)
                 (or (cdr (assoc string
                                 '(("*" . :wild)
                                   ("?" . :char))
                                 :test #'string=))
                     string))
               (ppcre:split '(:sequence
                              (:negative-lookbehind #\\)
                              (:register (:alternation #\* #\?)))
                            string
                            :with-registers-p t))
          :test #'string=))

答案 1 :(得分:5)

没有当前目录且没有主目录字符

便携式Common Lisp中不存在表示当前目录的.概念。这可能存在于特定的文件系统和特定的实现中。

同样~表示主目录不存在。某些实现可能会将它们识别为非可移植扩展。

在路径名字符串中,您有***作为通配符。这适用于绝对路径名和相对路径名。

默认路径名的默认值

Common Lisp有*default-pathname-defaults*,它为某些路径名操作提供了默认值。

<强>实施例

CL-USER 46 > (directory "/bin/*")
(#P"/bin/[" #P"/bin/bash" #P"/bin/cat"   ....   )

现在在上面已经略微未定义或分散了Unix上的实现:

  • 解决符号链接?
  • 包含“隐藏”文件?
  • 包含类型为?
  • 的文件

下一步:

CL-USER 47 > (directory "/bin/*sh")
(#P"/bin/zsh" #P"/bin/tcsh" #P"/bin/sh" #P"/bin/ksh" #P"/bin/csh" #P"/bin/bash")

使用相对路径名:

CL-USER 48 > (let ((*default-pathname-defaults* (pathname "/bin/")))
               (directory "*sh"))
(#P"/bin/zsh" #P"/bin/tcsh" #P"/bin/sh" #P"/bin/ksh" #P"/bin/csh" #P"/bin/bash")

主目录中的文件:

CL-USER 49 > (let ((*default-pathname-defaults* (user-homedir-pathname)))
              (directory "*"))

同样的:

CL-USER 54 > (directory (make-pathname :name "*"
                                       :defaults (user-homedir-pathname)))

/usr/local/及以下字段中查找以sh结尾的所有文件:

CL-USER 54 > (directory "/usr/local/**/*sh")

使用MAKE-PATHNAME构建路径名

.h下找到所有/usr/local/个文件的三种方法:

(directory "/usr/local/**/*.h")

(directory (make-pathname :name :wild
                          :type "h"
                          :defaults "/usr/local/**/")

(directory
   (make-pathname :name :wild
                  :type "h"
                  :directory '(:ABSOLUTE "usr" "local" :WILD-INFERIORS)))

<强>问题

跨平台('windows','unix','mac',...)甚至在同一平台(尤其是'windows'或'unix')上有很多不同的实现解释。像路径名中的unicode这样的东西会产生额外的复杂性 - 而不是在CL标准中描述。

我们仍然有很多不同的文件系统(https://en.wikipedia.org/wiki/List_of_file_systems),但它们的功能与Common Lisp设计时的典型不同或不同。实现可能已经跟踪了这些变化,但不一定是以便携式方式。