Dav*_* B. 10 python regex find
我想找到其全名(相对,虽然绝对也很好)的文件匹配给定的正则表达式(即,像glob模块一样,但是对于正则表达式匹配而不是shell通配符匹配).使用find,人们可以这样做,例如:
find . -regex ./foo/\w+/bar/[0-9]+-\w+.dat
Run Code Online (Sandbox Code Playgroud)
当然,我可以使用findvia os.system(...)或者os.exec*(...),但我正在寻找纯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
Run Code Online (Sandbox Code Playgroud)
但这效率低下.其内容与正则表达式不匹配的子树(例如,./foo/\w+/baz/继续上面的示例)是不必要地走的.理想情况下,这些子树应该从步行中删除; 不应遍历路径名不是正则表达式的部分匹配的任何子目录.(我猜想GNU find实现了这样的优化,但我还没有通过测试或源代码细读来证实这一点.)
有没有人知道基于强大的正则表达式的Python实现find,理想情况下是子树修剪优化?我希望我只是错过了os.path模块或某些第三方模块中的方法.
来自help(os.walk):
当topdown为true时,调用者可以就地修改dirnames列表(例如,通过del或slice赋值),walk将只递归到名称保留在dirnames中的子目录中; 这可以用来修剪搜索...
因此,一旦dirnames确定子目录(列在其中)是不允许的,就应该从中删除它dirnames.这将产生您正在寻找的子树修剪.(请务必先从尾端查找del项目dirnames,这样就不会更改要删除的剩余项目的索引.)
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')
Run Code Online (Sandbox Code Playgroud)
使用如下目录结构运行脚本:
~/test% tree .
.
|-- foo
| `-- baz
| |-- bad
| | |-- bad1.txt
| | `-- badbad
| | `-- bad2.txt
| `-- bar
| |-- 1-good.dat
| `-- 2-good.dat
`-- tmp
|-- 000.png
|-- 001.png
`-- output.gif
Run Code Online (Sandbox Code Playgroud)
产量
pruning tmp
pruning foo/baz/bad
foo/baz/bar/2-good.dat
foo/baz/bar/1-good.dat
Run Code Online (Sandbox Code Playgroud)
如果取消注释"检查"打印语句,很明显修剪过的目录不会被移动.
| 归档时间: |
|
| 查看次数: |
5226 次 |
| 最近记录: |