使用正则表达式输入创建列表
我正在用 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 个回答
如果你只是想避开所有符合这个规则的文件夹,你可以这样做:
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]
在之前的建议基础上,你可以使用 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])
与其往 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 的《正则表达式烹饪书》。