在Python中按范围进行带零填充的全局匹配

1 投票
2 回答
1613 浏览
提问于 2025-04-18 01:45

有个关于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

最简单的方法就是:

  1. 找到所有以 sync 开头的文件
  2. 根据数字部分对文件进行排序
  3. 把它们分成每组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)

但对于这样的任务,使用简单的列表推导式也完全没问题。

撰写回答