Python 批处理文件重命名:使用正则表达式时填充时间为零?

Python 批处理文件重命名:使用正则表达式时填充时间为零?,python,regex,rename,filenames,Python,Regex,Rename,Filenames,我有一整套文件(10.000+),包括文件名中的日期和时间。问题是日期和时间不是零填充的,导致排序问题 文件名的格式为:输出5-11-2018 9h0m.xml 我希望它的格式是:output 05-11-2018 09h00m.xml 我搜索了不同的解决方案,但大多数似乎都使用拆分字符串然后重新组合它们。这看起来相当麻烦,因为在我的例子中,日、月、小时和分钟需要分开,填充,然后重新组合 我想正则表达式可能会给我一些更好的解决方案,但我不太明白 我根据Wiktor Stribiżew的建议编辑了

我有一整套文件(10.000+),包括文件名中的日期和时间。问题是日期和时间不是零填充的,导致排序问题

文件名的格式为:
输出5-11-2018 9h0m.xml

我希望它的格式是:
output 05-11-2018 09h00m.xml

我搜索了不同的解决方案,但大多数似乎都使用拆分字符串然后重新组合它们。这看起来相当麻烦,因为在我的例子中,日、月、小时和分钟需要分开,填充,然后重新组合

我想正则表达式可能会给我一些更好的解决方案,但我不太明白

我根据Wiktor Stribiżew的建议编辑了我的原始代码,您不能在替换中使用正则表达式,而是使用组:

import os
import glob
import re

old_format = 'output [1-9]-11-2018 [1-2]?[1-9]h[0-9]m.xml'
dir = r'D:\Gebruikers\<user>\Documents\datatest\'   

old_pattern = re.compile(r'([1-9])-11-2018 ([1-2][1-9])h([0-9])m')

filelist = glob.glob(os.path.join(dir, old_format))
for file in filelist:
    print file
    newfile = re.sub(old_pattern, r'0\1-11-2018 \2h0\3m', file)
    os.rename(file, newfile)
导入操作系统
导入glob
进口稀土
旧_格式='输出[1-9]-11-2018[1-2]?[1-9]h[0-9]m.xml'
dir=r'D:\Gebruikers\\Documents\datatest\n
旧模式=重新编译(r'([1-9])-2018年11月([1-2][1-9])h([0-9])m')
filelist=glob.glob(os.path.join(dir,旧格式))
对于文件列表中的文件:
打印文件
newfile=re.sub(旧模式,r'0\1-11-2018\2h0\3m',文件)
重命名(文件,新文件)

但这仍然不能完全像我希望的那样工作,因为它在10小时内不会改变。我还可以尝试什么?

您可以使用lambda表达式将文件名中的数字填入
.zfill(2)
,该表达式作为替换参数传递给
re.sub
方法

另外,修复regex模式以允许1或2个数字:
(3[01]|[12][0-9]|[1-9])
用于日期,
(2[0-3]|[10]?\d)
用于一小时(24小时),以及
([0-5]?[0-9])
用于分钟:

old_pattern = re.compile(r'\b(3[01]|[12][0-9]|0?[1-9])-11-2018 (2[0-3]|[10]?\d)h([0-5]?[0-9])m')

然后使用:

for file in filelist:
    newfile = re.sub(old_pattern, lambda x: '{}-11-2018 {}h{}m'.format(x.group(1).zfill(2), x.group(2).zfill(2), x.group(3).zfill(2)), file)
    os.rename(file, newfile)
请参阅Python文档:

如果repl是一个函数,则会为模式的每个非重叠出现调用它。函数接受单个匹配对象参数,并返回替换字符串


为了简单起见,我建议使用更通用的旧模式,假设您的文件名只在数字上出现错误:

由于与需要在任何位置转换但在其他字段中为两位数的一位数字段匹配的文件名组合将需要一个长正则表达式来更明确地列出,因此我建议使用更简单的组合来匹配要重命名的文件,它假设目录中只有这种匹配类型的文件,因为它会更广泛地打开它,以便更简单地一目了然地写入和读取-查找文件名中的任何单个数字字段(一个或多个)-即非数字、数字、非数字:

old_format=r'output\.\D\D.\.xml'

然后,固定re.sub语句可以是:

newfile=re.sub(r'\D(\D)[hm-]',lambda x:x.group()[0]+x.group()[1].zfill(2)+x.group()[2],文件)

这还将捕获unicode非ascii数字,除非设置了适当的re模块标志


如果年份(例如2018年)可能仅被指定为“18”,则需要对其进行特殊处理-可以是单独的情况,还可以在re.sub regex模式集中添加一个空格(即
[-hm]
)。

在替换中不能使用regex,请在regex中使用组和占位符,如
\1
\2
,等,以参考这些值。请参阅
re.sub
docs。谢谢,这至少为我指明了一些正确的方向。这帮助我制定了一个re.sub,它至少可以更改部分文件名。但是我真的很想找到一个解决方案,根据已经存在的位数(1->01和12->12),零填充所有内容。你有更多的指针吗?不要使用
r'0\1-11-2018\2h0\3m'
,而是使用
lambda x:'{}-11-2018{}h{}m'。格式(x.group(1).zfill(2),x.group(2).zfill(2),x.group(3).zfill(2))
旧的模式需要更改,因为它需要两位数字。小时和分钟(或日/月)可以是个位数,需要修正。但您需要灵活,因为如果其他日期字段只有一位数字,您不希望有两位数字的日期字段导致其不匹配。用括号括起来的A | b表达式可以完成这项工作,但会到处重复一些正则表达式。我不喜欢重复调用.group(),但它是lambda,因此无法保存在局部函数变量中。可以转换成一个,或者检查是否有更直接的访问。另一种选择是lambda中的mini re.sub()(我也认为这很难看)