提问人:izb 提问时间:10/2/2008 更新时间:11/13/2014 访问量:3578
您将如何在 python 中实现 ant 样式集来选择文件组?
How would you implement ant-style patternsets in python to select groups of files?
问:
Ant 有一种很好的方法来选择文件组,最方便的是使用 ** 来指示目录树。例如
**/CVS/* # All files immediately under a CVS directory.
mydir/mysubdir/** # All files recursively under mysubdir
更多示例可以在这里看到:
http://ant.apache.org/manual/dirtasks.html
您将如何在 python 中实现这一点,以便您可以执行以下操作:
files = get_files("**/CVS/*")
for file in files:
print file
=>
CVS/Repository
mydir/mysubdir/CVS/Entries
mydir/mysubdir/foo/bar/CVS/Entries
答:
os.walk
是你的朋友。查看 Python 手册中的示例
(https://docs.python.org/2/library/os.html#os.walk)并尝试从中构建一些东西。
若要将“”与获得的文件名进行匹配,可以执行如下操作:**/CVS/*
def match(pattern, filename):
if pattern.startswith("**"):
return fnmatch.fnmatch(file, pattern[1:])
else:
return fnmatch.fnmatch(file, pattern)
在 中,“*”匹配任何内容(包括斜杠)。fnmatch.fnmatch
评论
是的。正如已经建议的那样,你最好的选择是使用'os.walk'。或者,也许可以围绕“glob”和“fnmatch”模块编写包装器。
os.walk 是您最好的选择。我用.svn做了下面的例子,因为我有这个方便的东西,而且效果很好:
import re
for (dirpath, dirnames, filenames) in os.walk("."):
if re.search(r'\.svn$', dirpath):
for file in filenames:
print file
一旦你遇到一个,你将不得不递归整个目录结构,所以我认为在这一点上,最简单的方法是使用 os.walk 遍历目录,构造一个路径,然后检查它是否与模式匹配。您可以通过以下方式转换为正则表达式:**
def glob_to_regex(pat, dirsep=os.sep):
dirsep = re.escape(dirsep)
print re.escape(pat)
regex = (re.escape(pat).replace("\\*\\*"+dirsep,".*")
.replace("\\*\\*",".*")
.replace("\\*","[^%s]*" % dirsep)
.replace("\\?","[^%s]" % dirsep))
return re.compile(regex+"$")
(但请注意,这并不是那么完整的功能 - 例如,它不支持样式 glob 模式,尽管这可能会被添加)。(第一个匹配是涵盖匹配等情况,以及必须在尾部匹配。[a-z]
\*\*/
\*\*/CVS
./CVS
\*\*
但是,显然,在不处理模式时,您不希望递归当前目录下的所有内容,因此我认为您需要一个两阶段方法。我还没有尝试过实现以下内容,并且可能有一些极端情况,但我认为它应该有效:**
拆分目录分隔符上的模式。即
pat.split('/') -> ['**','CVS','*']
递归目录,并查看此级别的模式的相关部分。即。.
n levels deep -> look at pat[n]
如果切换到上述策略:
pat[n] == '**'
- 用
dirsep.join(pat[n:])
- 转换为正则表达式
glob\_to\_regex()
- 递归地遍历当前目录,建立相对于您开始的级别的路径。如果路径与正则表达式匹配,则让出它。
os.walk
- 用
如果 pat 不匹配,并且它是模式中的最后一个元素,则生成所有匹配的文件/目录
"**"
glob.glob(os.path.join(curpath,pat[n]))
如果 pat 不匹配,并且它不是模式中的最后一个元素,则对于每个目录,检查它是否匹配(使用 glob)。如果是这样,请向下递归,增加深度(这样它就会查看
"**"
pat[n]
pat[n+1]
)
“waf”构建系统源代码中有一个实现。http://code.google.com/p/waf/source/browse/trunk/waflib/Node.py?r=10755#471也许这应该被包装在自己的库中?
对不起,这是您 OP 之后很长一段时间。我刚刚发布了一个 Python 包,它完全可以做到这一点 - 它被称为 Formic,可以在 PyPI Cheeseshop 上找到。使用 Formic,您的问题可以通过以下方式解决:
import formic
fileset = formic.FileSet(include="**/CVS/*", default_excludes=False)
for file_name in fileset.qualified_files():
print file_name
有一个轻微的复杂性:default_excludes。Formic,就像 Ant 一样,默认排除 CVS 目录(因为在大多数情况下,从它们收集文件进行构建是危险的),问题的默认答案将导致没有文件。设置 default_excludes=False 将禁用此行为。
评论
easy_install
pip
virtualenv
上一个:版本化词典的接口
下一个:用于将回溯转换为其异常的库?
评论