基于特定标准的路径排序

问题描述 投票:0回答:2

我有四个文件(或任意数量的文件)命名为

file_V2023.2.2_0.txt
file_V2023.2.2_1.txt
file_V2023.2.3_0.txt
file_V2023.2.3_1.txt

如果我这样做

from pathlib import Path
output_path = Path("./")
for video_path in sorted(output_path.glob("*.txt")):
    print(video_path)

我得到上面的订单。

有什么办法可以得到以下订单:

file_V2023.2.2_0.txt
file_V2023.2.3_0.txt
file_V2023.2.2_1.txt
file_V2023.2.3_1.txt
python glob pathlib
2个回答
0
投票

sorted()
函数有一个
key
参数,你给它一个函数,为你正在排序的东西提供排序键。

所以:

import re


names = [
    'file_V2023.2.2_0.txt',
    'file_V2023.2.3_0.txt',
    'file_V2023.2.2_1.txt',
    'file_V2023.2.3_1.txt'
]


name_pattern = re.compile('.*\.(\d+)\.(\d+)_(\d+)\.txt')
def get_key(name):
    a, b, c = re.match(name_pattern, name).groups()
    return int(a), int(c), int(b)  # reordering here


print(sorted(names, key=get_key))

输出:

['file_V2023.2.2_0.txt', 'file_V2023.2.3_0.txt', 'file_V2023.2.2_1.txt', 'file_V2023.2.3_1.txt']

正则表达式对于分解名称非常有用,因为它也适用于像

file_V2023.10.2_99.txt
这样的名称。正则表达式中用括号 (
(
,
)
) 括起来的部分作为单独的组进行匹配,然后用
.groups()
检索它们,因为它们是三个,所以它们可以分布在
a, b, c
上。

匹配的数字字符串(例如,对于

'file_V2023.2.3_1.txt'
,它们将是
'2'
'3'
'1'
)被转换为
int
的原因,是为了确保像
'19'
这样的东西最终会结束after
'2'
而不是之前,因为
'1'
'19'
开头的
'2'
字母数字之前。

请注意,调用

re.compile
只是为了提高效率。这样,正则表达式只需编译一次,而不是每次调用函数时。但是如果你想让代码更短,或者避免访问全局,这也是一样的:

def get_key(name):
    a, b, c = re.match('.*\.(\d+)\.(\d+)_(\d+)\.txt', name).groups()
    return int(a), int(c), int(b)  # reordering here

另请注意,此示例假设数字是 only 您排序的依据,因此仅返回整数值的 3 元组作为排序键。如果您有像

'afile_V2023.2.3_0.txt'
'bfile_V2023.2.2_0.txt'
这样的名字,并且您希望
'afile'
出现在
'bfile'
之前,尽管它们的编号是这样的,这行得通:

name_pattern = re.compile('(.*)\.(\d+)\.(\d+)_(\d+)\.txt')
def get_key(name):
    t, a, b, c = re.match(name_pattern, name).groups()
    return t, int(a), int(c), int(b)

也就是说,您当然可以在排序键中混合类型,只要 Python 知道如何对它们进行排序。


0
投票

其实给定你的文件名设计,没必要用正则表达式。

这只是一个多排序案例,您首先按主要版本排序,然后按

_
之后的次要版本排序。

所以你可以简单地调用 sort 两次:

names = [
    'file_V2023.2.2_0.txt',
    'file_V2023.2.3_1.txt',
    'file_V2023.2.3_0.txt',
    'file_V2023.2.2_1.txt',
]


# First sort.
names.sort()
# Second sort, sort by anything after the second '_'.
names.sort(key=lambda name: name.split('_')[2])

print(names)
© www.soinside.com 2019 - 2024. All rights reserved.