行政/财务的文件夹经常是这样:合同_2024年3月-张三 最终版(2).pdf、微信图片_20240312102233.jpg、报销单 2024-4 王五(1).xlsx 混在一起。下面这份脚本从文件名里自动提取类别 + 日期,重命名成 20240315-合同-张三.pdf 并归入子目录。本次完整实跑过,不是纸面代码。
import os, re, shutil
from datetime import datetime
# 14位连写(日期+时间)必须放在8位前面,否则只吃走前8位剩下6位数字残留
DATE_RES = [
re.compile(r'(?<!\\d)(20\\d{2})(\\d{2})(\\d{2})\\d{6}(?!\\d)'), # 20240312102233
re.compile(r'(?<!\\d)(20\\d{2})(\\d{2})(\\d{2})(?!\\d)'), # 20240312
re.compile(r'(?<!\\d)(20\\d{2})[年./\\-](\\d{1,2})[月./\\-](\\d{1,2})日?(?!\\d)'), # 2024年3月15日 / 2024.03.15
]
KEYWORDS = ['合同', '发票', '报销单', '照片']
def is_junk(name):
# 三类垃圾文件:任何位置的隐藏文件 / Office锁文件(~$可能不在开头!) / 波浪号临时文件
return name.startswith('.') or '~$' in name or name.startswith('~')
def new_name(name, cls, d, raw):
stem, ext = os.path.splitext(name)
if raw:
stem = stem.replace(raw, '') # 剥掉已提取的日期串
stem = re.sub(r'\\s*\\(\\d+\\)$', '', stem) # 去Windows重复下载尾缀 (2)
stem = stem.replace(cls, '', 1) # 类别词只保留一份做前缀
stem = re.sub(r'[\\s_\\-]+', '', stem)
return '-'.join(p for p in [d, cls, stem] if p) + ext.lower()
for fn in os.listdir(SRC):
if is_junk(fn):
continue
cls = next((k for k in KEYWORDS if k in fn),
'照片' if re.match(r'^(IMG|微信图片|DSC)', fn, re.I) else '未分类')
d = raw = None
for rx in DATE_RES:
m = rx.search(fn)
if m:
raw = m.group(0)
try:
d = datetime(*map(int, m.groups())).strftime('%Y%m%d')
except ValueError:
d = None # 非法日期不猜,宁可置空
break
os.makedirs(dst_dir := os.path.join(OUT, cls), exist_ok=True)
dst = os.path.join(dst_dir, new_name(fn, cls, d, raw))
base, ext = os.path.splitext(dst); n = 1
while os.path.exists(dst): # 撞名不覆盖,追序号
dst = f'{base}-{n}{ext}'; n += 1
shutil.copy2(os.path.join(SRC, fn), dst)
微信图片_20240312102233.jpg 先被 8 位规则命中,提取出 20240312 后名字里残留 102233。必须把 14 位连写规则放在 8 位前面,正则列表是按顺序吃的。~$ 不一定在开头。Windows 某些版本生成的是 临时缓存~$报表.xlsx——startswith('~$') 拦不住,锁文件混进输出目录后用户一打开就报错。要用 '~$' in name 判断任意位置。隐藏文件同理:守卫用的 .seeded 被归档进了"未分类",startswith('.') 要拦全部而非只拦 .DS_Store。shutil.copy 会静默覆盖同名文件。两份 合同20240315李四.pdf 和 合同20240315李四(1).pdf 归一后同名,第二个会无声覆盖第一个——丢文件还不报错。必须写 while os.path.exists(dst) 循环追序号,并实测确认两份内容 md5 多重集一致(10进10出无一丢失)。replace(cls, '', 1) 只留前缀一份、日期串用 replace(raw, '') 剥掉,重命名才有意义。另外文件名里的 / 在 Windows 会自动换成 _,造测试数据时直接报 FileNotFoundError——路径分隔符是文件名的天然禁区。13个测试文件(含3类脏文件:隐藏文件×3、Office锁文件×2、目录×1;3种日期写法;同名撞名对)→ 10个有效文件全部归入 4 个类别子目录,日期/类别/姓名提取全对,撞名对变成 -1 后缀两个都在,5个垃圾文件全部跳过,连跑2次输出结构 md5 一致(幂等),输入输出内容 md5 多重集核对零丢失。
喵窝资源铺提供人工代做:发来你的文件夹(打包压缩即可),按你的规则批量重命名归档、清洗归类,19.9元/次起,交付前人工复核。(虚拟服务,交付后不退款;未达承诺免费重做)
更多批量处理干货:免费工具清单(邮件订阅版) · 全部文章