如何在Common Lisp中使用通配符搜索文件? [英] How to search for files with a wildcard in 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屋!