python - Python 中的 "find . -regex ..."或如何查找全名(路径+名称)与正则表达式匹配的文件?

标签 python regex find

我想找到其全名(相对的,虽然绝对也很好)匹配给定正则表达式的文件(即,像 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/

相关文章:

linux - 查找文件并移动其文件夹

python - Flask(Python)可以移植到Lua吗?

Python SSL 和 Unicode 域

python - 在 matplotlib 中创建两个完全独立的图并在它们之间来回切换

c++ - std::regex_replace 给了我意想不到的结果

linux - 如何在多个文件中搜索重复的未知字符串

python - 使用 pygame 库的简单 python 游戏的问题

python - 用于提取最后一个连字符之前的一定数量的字符的正则表达式

regex - 正则表达式匹配字符串中特定位置的相同单词

linux - find type -f 还返回匹配目录中的不匹配文件