在Python中按范围进行带零填充的全局匹配
有个关于Python中使用通配符的问题。
我有一个文件夹,里面有一些文件,名字是'sync_0001.tif','sync_0002.tif',一直到'sync_2400.tif'。我想把这些文件分成三个小列表:一个是前800个文件,第二个是中间800个文件,最后一个是最后800个文件。问题是这些文件名里有数字前面加了0。我不知道怎么用通配符来获取这些列表。第三个列表比较简单,因为那些文件名里没有0(s3=glob.glob('sync_[1601-2400].tif'))。前两个列表就比较麻烦,因为数字前面的0数量不一样。
我试过这样做,但出现了“坏的字符范围”的错误,我猜是因为那些0:
s1 = glob.glob('sync_' + '{[0001-0009], [0010-0099], [0100-0800]}' + '.tif')
s2 = glob.glob('sync_' + '{[0801-0999], [1000-1600]}' + '.tif')
然后我试着把0放到前面,但得到了一个空列表:
s1 = glob.glob('sync_' + '{000[1-9], 00[10-99], 0[100-800]}' + '.tif')
有什么好的方法来得到这三个列表吗?我开始觉得我对通配符的理解可能有问题,如果有人能帮我解答一下就太好了。谢谢!
2 个回答
0
最简单的方法就是:
- 找到所有以
sync
开头的文件 - 根据数字部分对文件进行排序
- 把它们分成每组800个文件
既然你已经知道怎么找到文件了,接下来的步骤就是:
import glob
import re
from itertools import izip_longest
# https://docs.python.org/2/library/itertools.html#recipes
def grouper(iterable, n, fillvalue=None):
"Collect data into fixed-length chunks or blocks"
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
def sorter(x):
return int(re.search('(\d+)',x).groups()[0])
files = glob.glob('sync*.tif')
sorted_files = sorted(files, key=sorter)
in_batches = list(grouper(sorted_files, 800))
因为模式总是 sync_
(在你编辑之后),你可以把上面的代码简化成下面这样:
files = glob.glob('sync_*.tif')
sorted_files = sorted(files, key=lambda x: int(x.split('_')[1]))
in_batches = list(grouper(sorted_files, 800))
2
fnmatch
模块是实现glob.glob()
功能的,但它并不够强大,无法满足你的需求。
你可以先获取所有的文件名,然后在排序后进行分组:
filenames = sorted(glob.glob('sync_[0-9][0-9][0-9][0-9].tif'))
这样做是因为你的数字是补零的,所以可以按照字典顺序进行排序。接下来进行分组:
s1 = [f for f in filenames if 0 < int(f[5:9]) <= 800]
s2 = [f for f in filenames if 800 < int(f[5:9]) <= 1600]
s3 = [f for f in filenames if 1600 < int(f[5:9]) <= 2400]
不过,读取目录的速度本来就比较慢。你可以通过只循环一次,并交换你要添加的内容,来提高效率:
target = s1 = []
s2 = []
s3 = []
for f in filenames:
num = int(f[5:9])
if num > 800:
target = s2
elif num > 1600:
target = s3
target.append(f)
但对于这样的任务,使用简单的列表推导式也完全没问题。