Ehv*_*nce 4 wildcard common-lisp 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
Run Code Online (Sandbox Code Playgroud)
如何用unix风格的通配符搜索文件?
如果它不是内置的,我会喜欢uiop的解决方案.也许有Osicat或cl-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"
Run Code Online (Sandbox Code Playgroud)
以下通过jpg扩展获取文件,但它还不是一个合适的通配符:
(directory *)
(#P"/home/vince/cl-cookbook/AppendixA.jpg"
#P"/home/vince/cl-cookbook/AppendixB.jpg"
#P"/home/vince/cl-cookbook/AppendixC.jpg")
Run Code Online (Sandbox Code Playgroud)
关于路径名的文档和make-pathname:http://gigamonkeys.com/book/files-and-file-io.html(没有提到通配符)
SBCL支持名称中的通配符.首先,创建一些文件:
(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))
Run Code Online (Sandbox Code Playgroud)
然后,列出包含"a"的所有文件:
CL-USER> (directory #P"/tmp/stack/*a*.txt")
(#P"/tmp/stack/abc.txt" #P"/tmp/stack/cadar.txt" #P"/tmp/stack/cdadr.txt")
Run Code Online (Sandbox Code Playgroud)
pathname包含特定于实现的(有效)名称组件:
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
Run Code Online (Sandbox Code Playgroud)
SBCL还定义sb-ext:map-directory了逐个处理文件,而不是首先收集列表中的所有文件.
如果您需要坚持使用标准路径名组件,则可以先directory使用普通通配符调用,然后过滤生成的列表:
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")
Run Code Online (Sandbox Code Playgroud)
...... wildcard可能基于正则表达式(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=))
Run Code Online (Sandbox Code Playgroud)
(注意:上面的负面反馈并不能消除逃逸的反斜杠)
(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))))
Run Code Online (Sandbox Code Playgroud)
中级职能:
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)
Run Code Online (Sandbox Code Playgroud)
没有当前目录,也没有主目录字符
.便携式Common Lisp中不存在表示当前目录的概念。这可能存在于特定的文件系统和特定的实现中。
还~表示主目录不存在。在某些实现中,它们可能被视为非便携式扩展。
在路径名字符串中,您具有*和**作为通配符。这适用于绝对路径名和相对路径名。
默认为默认路径名
Common Lisp具有*default-pathname-defaults*为某些路径名操作提供默认值的功能。
例子
CL-USER 46 > (directory "/bin/*")
(#P"/bin/[" #P"/bin/bash" #P"/bin/cat" .... )
Run Code Online (Sandbox Code Playgroud)
现在,在上面已经有点不确定了,或者在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")
Run Code Online (Sandbox Code Playgroud)
使用相对路径名:
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")
Run Code Online (Sandbox Code Playgroud)
主目录中的文件:
CL-USER 49 > (let ((*default-pathname-defaults* (user-homedir-pathname)))
(directory "*"))
Run Code Online (Sandbox Code Playgroud)
相同:
CL-USER 54 > (directory (make-pathname :name "*"
:defaults (user-homedir-pathname)))
Run Code Online (Sandbox Code Playgroud)
查找以下所有以sh结尾的文件/usr/local/:
CL-USER 54 > (directory "/usr/local/**/*sh")
Run Code Online (Sandbox Code Playgroud)
使用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)))
Run Code Online (Sandbox Code Playgroud)
问题
甚至在同一平台(尤其是“ windows”或“ unix”)上,跨平台(“ windows”,“ unix”,“ mac”,...)的实现也有很多不同的解释。路径名中的诸如unicode之类的东西会增加额外的复杂性-在CL标准中没有描述。
我们仍然有很多不同的文件系统(https://en.wikipedia.org/wiki/List_of_file_systems),但是它们的功能与Common Lisp设计时的功能不同或不同。实现可能已经跟踪了更改,但不一定以可移植的方式进行。