7

是否有任何内置或直接的方法可以递归地匹配带有双星号的路径,例如像zsh那样?

例如,与

path = 'foo/bar/ham/spam/eggs.py'

我可以使用fnmatch来测试它

fnmatch(path, 'foo/bar/ham/*/*.py'

虽然,我希望能够做到:

fnmatch(path, 'foo/**/*.py')

我知道 fnmatch将其模式映射到 regex,所以在这种情况下,我可以使用其他模式滚动我自己的 fnmatch **,但也许有更简单的方法

4

4 回答 4

7

如果您仔细查看 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
于 2013-08-20T18:00:57.317 回答
4

对于适用于路径的 fnmatch 变体,您可以使用一个名为wcmatch的库,该库实现了一个函数,该函数使用与爬取文件系统globmatch相同的逻辑来匹配路径。glob您可以使用标志控制启用的功能,在这种情况下,我们启用GLOBSTAR**用于递归目录搜索)。

>>> from wcmatch import glob
>>> glob.globmatch('some/file/path/filename.txt', 'some/**/*.txt', flags=glob.GLOBSTAR)
True
于 2020-02-11T17:09:17.053 回答
3

如果您可以在不使用 os.walk 循环的情况下生活,请尝试:

glob2

甲酸

我个人使用 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) 
于 2013-11-06T21:38:45.207 回答
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
于 2020-01-18T02:24:43.533 回答