是否存在以双星号递归匹配路径的内置或直接方式,例如像zsh那样吗?
例如,使用
path = 'foo/bar/ham/spam/eggs.py'
我可以使用fnmatch来测试
fnmatch(path, 'foo/bar/ham/*/*.py'
虽然,我希望能够做到:
fnmatch(path, 'foo/**/*.py')
我知道fnmatch maps its pattern to regex,所以在单词中我可以使用额外的**
模式滚动我自己的fnmatch,但也许有更简单的方法
答案 0 :(得分:3)
如果仔细研究fnmatch源代码,它会将*
映射到.*
,因此不关心目录分隔符/
- 与UNIX shell不同:
while i < n:
c = pat[i]
i = i+1
if c == '*':
res = res + '.*'
elif c == '?':
res = res + '.'
elif c == '[':
...
因此
>>> fnmatch.fnmatch('a/b/d/c', 'a/*/c')
True
>>> fnmatch.fnmatch('a/b/d/c', 'a/*************c')
True
答案 1 :(得分:3)
如果你可以不使用os.walk循环,请尝试:
我个人使用glob2:
import glob2
files = glob2.glob(r'C:\Users\**\iTunes\**\*.mp4')
从Python 3.5开始,本机glob模块支持递归模式匹配:
import glob
files = glob.iglob(r'C:\Users\**\iTunes\**\*.mp4', recursive=True)
答案 2 :(得分:2)
对于适用于路径的fnmatch变体,您可以使用名为wcmatch的库,该库实现了globmatch
函数,该函数以与glob
爬网文件系统相同的逻辑来匹配路径。您可以使用标志来控制启用的功能,在这种情况下,我们启用GLOBSTAR
(使用**
进行递归目录搜索)。
>>> from wcmatch import glob
>>> glob.globmatch('some/file/path/filename.txt', 'some/**/*.txt', flags=glob.GLOBSTAR)
True
答案 3 :(得分:1)
此代码段增加了对**的兼容性
import re
from functools import lru_cache
from fnmatch import translate as fnmatch_translate
@lru_cache(maxsize=256, typed=True)
def _compile_fnmatch(pat):
# fixes fnmatch for recursive ** (for compatibilty with Path.glob)
pat = fnmatch_translate(pat)
pat = pat.replace('(?s:.*.*/', '(?s:(^|.*/)')
pat = pat.replace('/.*.*/', '.*/')
return re.compile(pat).match
def fnmatch(name, pat):
return _compile_fnmatch(str(pat))(str(name)) is not None