我有四个文件(或任意数量的文件)命名为
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
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 知道如何对它们进行排序。
其实给定你的文件名设计,没必要用正则表达式。
这只是一个多排序案例,您首先按主要版本排序,然后按
_
之后的次要版本排序。
所以你可以简单地调用 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)