如何在Common Lisp中使用通配符搜索文件? [英] How to search for files with a wildcard in Common Lisp?

查看:408
本文介绍了如何在Common Lisp中使用通配符搜索文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am not satisfied to find files matching a string like this:

(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样式通配符的文件?

How would one search for files with unix-style wildcards ?

如果它不是内置的,我会喜欢用户界面.也许有 Osicat

If it is not built-in, I'd enjoy a solution with uiop. Maybe there is with Osicat or cl-fad (with which it doesn't seem so, the documentation oftentimes says "non-wild pathname").

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

Bonus if it is possible to use the double wildcard to traverse directories recursively (./**/*.jpg).

编辑:我尝试了(directory #p"./**/*.jpg")的变体,并且返回nil :(也尝试了#p".*jpg"#p"./.*jpg",…

edit: I have tried variants of (directory #p"./**/*.jpg") and it returns nil :( Also tried #p".*jpg", #p"./.*jpg",…

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


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

以下内容通过jpg扩展名获取了我的文件,但这还不是合适的通配符:

The following gets me files by jpg extension, but it isn't a proper wildcard yet:

(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 (未提及通配符)

Documentation on pathnames and make-pathname: http://gigamonkeys.com/book/files-and-file-io.html (no mentions of wildcards)

推荐答案

SBCL

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

SBCL

SBCL supports wildcards in names. First, create some files:

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

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

Then, list all files that contains an "a":

CL-USER> (directory #P"/tmp/stack/*a*.txt")
(#P"/tmp/stack/abc.txt" #P"/tmp/stack/cadar.txt" #P"/tmp/stack/cdadr.txt")

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

The pathname contains an implementation-specific (valid) name component:

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

SBCL还定义了sb-ext:map-directory,该文件一个接一个地处理文件,而不是首先收集列表中的所有文件.

SBCL also defines sb-ext:map-directory, which process files one by one, instead of first collecting all files in a list.

如果需要使用标准路径名组件,则可以先使用普通通配符调用directory,然后过滤结果列表:

If you need to stick to standard pathname components, you can first call directory with normal wildcards, and filter the resulting list:

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可能基于正则表达式( PPCRE ):

... where wildcard might be based on regex (PPCRE):

(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=))

(注意:上面的否定性查找不会不会消除转义的反斜杠)

(note: the above negative lookbehind does not eliminate escaped backslashes)

(defun wildcard-regex (wildcard)
  `(:sequence
    :start-anchor
    ,@(loop
        for token in wildcard
        collect (case token
                  (:char :everything)
                  (:wild '(:greedy-repetition 0 nil :everything))
                  (t token)))
    :end-anchor))

(defun wildcard (string)
  (let ((scanner (ppcre:create-scanner
                  (wildcard-regex (parse-wildcard string)))))
    (lambda (string)
      (ppcre:scan scanner string))))

中间功能:

CL-USER> (parse-wildcard "*a*a\\*a?\\?a")
(:WILD "a" :WILD "a\\*a" :CHAR "\\?a")

CL-USER> (wildcard-regex (parse-wildcard "*a*a\\*a?\\?a"))
(:SEQUENCE :START-ANCHOR #1=(:GREEDY-REPETITION 0 NIL :EVERYTHING) "a" #1# "a\\*a" :EVERYTHING "\\?a" :END-ANCHOR)

这篇关于如何在Common Lisp中使用通配符搜索文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆