使用正则表达式输入创建列表

2 投票
3 回答
671 浏览
提问于 2025-04-18 17:57

我正在用 Python 2.7.7 的 os.walk 方法搜索一个非常复杂的目录树,想要通过在结果目录中进行修剪来限制搜索范围。

import os,re
dirExclude = set(['amip4K','amip4xCO2','aqua4K','aqua4xCO2'])
for (path,dirs,files) in os.walk(inpath,topdown=True):
     dirs[:] = [d for d in dirs if d not in dirExclude]
     # Do something

我想把任何符合正则表达式 r'decadal[0-9]{4}' 的内容添加到这个 dirExclude 列表/集合中,但我不知道怎么在我的列表/集合定义中最好地使用正则表达式。

有什么建议吗?或者有没有更有效的方法来使用 os.walk 函数?

经过一些建议,上面的内容可以改进为:

import os,re
dirExclude = set(['amip4K','amip4xCO2','aqua4K','aqua4xCO2'])
decExclude = re.compile(r'decadal[0-9]{4}')
for (path,dirs,files) in os.walk(inpath,topdown=True):
     dirs[:] = [d for d in dirs if d not in dirExclude and not re.search(decExclude,d)]
     # Do something

在研究 dir[:] =dir = 的赋值方式后,发现 [:] 是必要的,这样 os.walk 才能使用经过修剪的目录列表,而不是完整的(未修剪的)目录列表。

3 个回答

0

如果你只是想避开所有符合这个规则的文件夹,你可以这样做:

d_re = re.compile(r'decadal[0-9]{4}')
dirs = [d for d in dirs if d_re.match(d) is None]

你可以在最后获取所有被忽略的文件,方法是:

 dirExclude = dirExclude.union(d for d in dirs if d not in dirExclude)

或者

[dirExclude.add(d) for d in dirs if d not in dirExclude]
1

在之前的建议基础上,你可以使用 ifilterfalse(在 Python 3.x 中是 filterfalse)来高效地根据正则表达式进行筛选:

from itertools import ifilterfalse
import re
import os

exclude = {'foo', 'bar', 'baz'}
expr = re.compile(r'decadal\d{4}')
for (path, dirs, files) in os.walk(inpath):
    dirs[:] = set(ifilterfalse(expr.match, dirs)) - exclude

还有一些补充说明:

  • 仅仅使用 dir = [alist] 是不够的,因为这只会改变 本地 标签 dir 指向的内容(也就是说,它不再指向 os.walk 使用的 dirs 列表)。你 必须 修改 os.walk 所引用的实际 dirs 列表。你可以像上面那样,通过切片赋值操作来做到这一点。这基本上等同于这个表达式:dirs.__setitem__(slice(None, None), [alist])
1

与其往 dirExclude 里添加内容,不如直接检查一下目录名 d 是否符合 r'decadal[0-9]{4}' 这个模式呢?

我想的方式是这样的:

import re
dirExclude = set(['amip4K','amip4xCO2','aqua4K','aqua4xCO2'])
exre = re.compile(r'decadal[0-9]{4}')
for (path,dirs,files) in os.walk(inpath,topdown=True):
     dirs = [d for d in dirs if d not in dirExclude and not exre.search(d)]
     # Do something

解释一下:

exre.search(d) 如果在 d 里找不到符合你正则表达式的内容,就会返回 None。这时 not None 会被判断为 True。如果找到了,exre.search(d) 会返回一个 MatchObject,这时 not exre.search(d) 就会被判断为 False

编译正则表达式是可选的。如果不编译,你可以直接使用:

exre = r'decadal[0-9]{4}'

还有:

dirs = [d for d in dirs if d not in dirExclude and not re.search(exre, d)]

编译正则表达式在你需要多次使用的时候会很有用,这样就只需要编译一次。不过大多数情况下,你不会感觉到太大区别,因为即使你不手动编译,Python 也会自动缓存最近使用的正则表达式。具体来说,它会缓存最后使用的一百个正则表达式,不过我得到的唯一参考是 Jan Goyvaerts 和 Steven Levithan 的《正则表达式烹饪书》。

撰写回答