我想找到其全名(相对的,虽然绝对也很好)匹配给定正则表达式的文件(即,像 glob
模块,但用于正则表达式匹配而不是 shell 通配符匹配).使用 find
,例如:
find . -regex ./foo/\w+/bar/[0-9]+-\w+.dat
当然,我可以通过os.system(...)
或os.exec*(...)
使用find
,但我正在寻找纯 Python 解决方案。以下代码结合了 os.walk(...)
和 re
模块正则表达式是一个简单的 Python 解决方案。 (它不够健壮,遗漏了许多(不那么极端的)极端情况,但足以满足我的一次性使用目的,为一次性数据库插入定位特定数据文件。 )
import os
import re
def find(regex, top='.'):
matcher = re.compile(regex)
for dirpath, dirnames, filenames in os.walk(top):
for f in filenames:
f = os.path.relpath(os.path.join(dirpath, f), top)
if matcher.match(f):
yield f
if __name__=="__main__":
top = "."
regex = "foo/\w+/bar/\d+-\w+.dat"
for f in find(regex, top):
print f
但这是低效的。内容无法与正则表达式匹配的子树(例如,./foo/\w+/baz/
,继续上面的示例)被不必要地遍历。理想情况下,这些子树应该从 walk 中剪掉;不应遍历路径名与正则表达式不部分匹配的任何子目录。 (我猜测 GNU find
实现了这样的优化,但我还没有通过测试或源代码细读来证实这一点。)
有谁知道基于正则表达式的健壮的 find
的 Python 实现,最好是子树修剪优化?我希望我只是缺少 os.path
模块或某些第三方模块中的方法。
最佳答案
来自 help(os.walk)
:
When topdown is true, the caller can modify the dirnames list in-place (e.g., via del or slice assignment), and walk will only recurse into the subdirectories whose names remain in dirnames; this can be used to prune the search...
因此,一旦某个子目录(列在dirnames
中)被确定为 Not Acceptable ,就应该将其从dirnames
中删除。这将产生您正在寻找的子树修剪。 (一定要先从尾端 dirnames
del
项目,这样你就不会更改要删除的剩余项目的索引。)
import os
import re
def prune(regex,top='.'):
sep=os.path.sep
matcher = re.compile(regex)
pieces=regex.split(sep)
partial_matchers = map(
re.compile,
(sep.join(pieces[:i+1]) for i in range(len(pieces))))
for root, dirs, files in os.walk(top,topdown=True):
for i in reversed(range(len(dirs))):
dirname=os.path.relpath(os.path.join(root,dirs[i]), top)
dirlevel=dirname.count(sep)
# print(dirname,dirlevel,sep.join(pieces[:dirlevel+1]))
if not partial_matchers[dirlevel].match(dirname):
print('pruning {0}'.format(
os.path.relpath(os.path.join(root,dirs[i]), top)))
del dirs[i]
for filename in files:
filename=os.path.relpath(os.path.join(root,filename))
# print('checking {0}'.format(filename))
if matcher.match(filename):
print(filename)
if __name__=='__main__':
prune(r'foo/\w+/bar/\d+-\w+.dat')
运行具有如下目录结构的脚本:
~/test% tree .
.
|-- foo
| `-- baz
| |-- bad
| | |-- bad1.txt
| | `-- badbad
| | `-- bad2.txt
| `-- bar
| |-- 1-good.dat
| `-- 2-good.dat
`-- tmp
|-- 000.png
|-- 001.png
`-- output.gif
产量
pruning tmp
pruning foo/baz/bad
foo/baz/bar/2-good.dat
foo/baz/bar/1-good.dat
如果您取消注释“checking”打印语句,很明显修剪后的目录不会被遍历。
关于python - Python 中的 "find . -regex ..."或如何查找全名(路径+名称)与正则表达式匹配的文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6798097/