
最近在整理本地音乐库时发现很多从不同渠道下载的MV或现场表演视频文件名五花八门像【CORTIS】高清4K完整版 251214 MIC DROP (COVER) - CORTIS MARTIN 横版4K.mp4这种包含大量冗余信息如发布者、分辨率、日期、版本说明的情况非常普遍。手动一个个重命名不仅效率低下而且容易出错。对于音乐爱好者、视频整理者或自媒体工作者来说一套自动化的、基于规则的文件重命名工具能极大提升工作效率。本文将分享如何利用 Python 从零开始构建一个灵活、强大的视频文件智能重命名脚本实现从混乱命名到“歌手 - 歌曲名.mp4”这类整洁格式的自动转换。1. 项目背景与核心需求分析在数字媒体管理中规范的文件命名至关重要。它不仅能快速定位文件也便于软件如音乐播放器、视频编辑软件正确识别元数据。我们面临的典型文件名通常混杂了多种元素发布者/频道信息如【CORTIS】、CORTIS MARTIN质量与版本描述如高清4K完整版、横版4K、COVER日期标识如251214(可能表示2025年12月14日)核心内容如MIC DROP分隔符杂乱使用-、_、【】、()、空格等。我们的核心目标是提取出“歌手或主要标识”和“歌曲名或视频核心主题”并按照统一的模板进行重命名。同时脚本需要足够健壮以应对各种命名格式的变体。核心需求拆解批量处理能够扫描指定目录下的所有目标视频文件如.mp4,.mkv,.avi。智能解析通过正则表达式Regex规则从原始文件名中剥离冗余信息提取关键部分。规则可配置允许用户自定义需要删除的常见冗余词如“完整版”、“高清”、“COVER”等。安全第一重命名操作必须是“预演”或“可撤销”的避免误操作导致文件丢失。应先打印重命名计划经确认后再执行。格式统一最终生成如CORTIS - MIC DROP.mp4这样简洁的命名。2. 环境准备与工具选择本项目主要使用 Python 标准库无需安装复杂的第三方依赖具有很好的跨平台性。编程语言Python 3.6 或更高版本。核心库os用于遍历目录、处理文件路径和执行重命名操作。re用于定义和匹配正则表达式实现文件名的智能解析。sys用于处理命令行参数如果扩展为命令行工具。开发环境任何文本编辑器或 IDE如 VSCode、PyCharm均可。操作系统Windows, macOS, Linux 均可运行。项目结构预览video_renamer/ ├── rename_engine.py # 核心重命名逻辑模块 ├── config.py # 配置文件存放冗余词列表、命名模板等 └── main.py # 主程序入口调用引擎并执行3. 核心技术正则表达式解析策略正则表达式是解决此类文本解析问题的利器。我们需要设计一套规则来匹配和替换文件名中的特定模式。3.1 定义需要清理的“噪音”模式首先我们将常见的冗余信息归类并用正则表达式表示# 在 config.py 或 rename_engine.py 中定义 PATTERNS_TO_REMOVE [ r【.*?】, # 匹配中文方括号及其内部内容如【CORTIS】 r\[.*?\], # 匹配英文方括号及其内部内容 r高清[0-9]*K?, # 匹配“高清”、“高清4K”等 r[0-9]{6}, # 匹配6位纯数字如251214需谨慎可能误伤歌曲名中的数字 r完整版, r横版|竖版, rCOVER, r^\s|\s$, # 匹配开头和结尾的空格 # 可以继续添加更多模式... ]3.2 设计文件名提取逻辑对于【CORTIS】高清4K完整版 251214 MIC DROP (COVER) - CORTIS MARTIN 横版4K这样的文件名我们的解析策略可以分步进行去除所有已定义的“噪音”模式。观察剩余内容通常核心结构是MIC DROP - CORTIS MARTIN或类似。我们可以假设最后一个-、–或—是分隔“歌曲名”和“歌手”的关键符号。如果存在分隔符则将其分割为两部分并分别清理两边的空格和可能的残留括号。如果没有明确分隔符则可能需要更复杂的启发式规则或将其整体作为歌曲名歌手留空。示例解析流程原始【CORTIS】高清4K完整版 251214 MIC DROP (COVER) - CORTIS MARTIN 横版4K去除噪音后MIC DROP - CORTIS MARTIN分割歌曲名MIC DROP,歌手CORTIS MARTIN最终格式化CORTIS MARTIN - MIC DROP.mp4有时我们可能希望简化歌手名例如从CORTIS MARTIN中只取CORTIS。这可以通过额外的规则如取第一个单词来实现。4. 完整实战案例构建重命名脚本让我们一步步实现这个重命名工具。4.1 创建项目结构与配置文件首先创建项目文件夹和文件。# config.py 配置文件定义需要移除的冗余词列表和命名模板 用户可以在此自定义规则 # 定义需要从文件名中移除的正则表达式模式列表 REMOVE_PATTERNS [ r【.*?】, r\[.*?\], r高清[0-9]*K?, r[0-9]{6}, # 注意此规则可能过于激进可根据实际情况调整或移除 r完整版, r横版|竖版, rCOVER, r^\s|\s$, # 去除首尾空格 ] # 定义最终的文件名格式模板 # 使用 {artist} 和 {title} 作为占位符 FILENAME_TEMPLATE {artist} - {title} # 支持的视频文件扩展名 VIDEO_EXTENSIONS {.mp4, .mkv, .avi, .mov, .wmv, .flv, .webm}4.2 实现核心重命名引擎这是脚本的核心包含文件名解析和重命名逻辑。# rename_engine.py import os import re import shutil from config import REMOVE_PATTERNS, FILENAME_TEMPLATE, VIDEO_EXTENSIONS class VideoRenamer: def __init__(self, directory): 初始化重命名器 :param directory: 要处理的目录路径 self.directory os.path.abspath(directory) if not os.path.isdir(self.directory): raise ValueError(f提供的路径不是有效的目录{self.directory}) def _clean_filename(self, original_name): 清理文件名移除冗余模式。 :param original_name: 原始文件名不含扩展名 :return: 清理后的文本 cleaned original_name for pattern in REMOVE_PATTERNS: cleaned re.sub(pattern, , cleaned, flagsre.IGNORECASE) # 将多个连续空格合并为一个并去除首尾空格 cleaned re.sub(r\s, , cleaned).strip() return cleaned def _parse_artist_and_title(self, cleaned_text): 从清理后的文本中解析出歌手和歌曲名。 默认使用最后一个“-”或“–”进行分割。 :param cleaned_text: 清理后的文件名文本 :return: (artist, title) 元组 # 查找最后一个横线分隔符支持普通短横线和长破折号 # 使用负向前瞻确保不会匹配到扩展名中的点号前 separator_match list(re.finditer(r ([-–—]) , cleaned_text)) if separator_match: last_separator separator_match[-1] sep_pos last_separator.start(1) # 获取分隔符本身的位置 # 根据分隔符位置分割字符串 title_part cleaned_text[:sep_pos].strip() artist_part cleaned_text[sep_pos 1:].strip() # 1 跳过分隔符本身 # 有时分隔符前后可能反了这里假设“歌手 - 歌曲名”是常见格式 # 但如果清理后是“歌曲名 - 歌手”我们可以做一个简单判断 # 如果 artist_part 看起来更像歌曲名更短、没有空格可以交换 # 这里采用一个简单策略如果 artist_part 包含空格且 title_part 不含空格可能反了 # 这是一个可优化的启发式规则 if not in title_part and in artist_part: # 可能反了交换 artist_part, title_part title_part, artist_part return artist_part, title_part else: # 没有找到明确分隔符将整个文本作为歌曲名歌手设为空 return , cleaned_text def analyze_directory(self, dry_runTrue): 分析目录中的视频文件生成重命名计划。 :param dry_run: 如果为True只打印计划而不执行。为False则实际重命名。 :return: 包含重命名计划的列表 rename_plan [] for filename in os.listdir(self.directory): file_path os.path.join(self.directory, filename) # 跳过目录和非视频文件 if not os.path.isfile(file_path): continue file_ext os.path.splitext(filename)[1].lower() if file_ext not in VIDEO_EXTENSIONS: continue # 分离文件名和扩展名 name_without_ext, ext os.path.splitext(filename) # 步骤1: 清理文件名 cleaned_name self._clean_filename(name_without_ext) # 步骤2: 解析歌手和歌曲名 artist, title self._parse_artist_and_title(cleaned_name) # 如果解析后歌曲名为空则使用清理后的整个名字作为歌曲名 if not title: title cleaned_name artist # 确保艺术家为空 # 步骤3: 应用模板生成新文件名 # 处理可能的空艺术家名 if artist: new_name_without_ext FILENAME_TEMPLATE.format(artistartist, titletitle) else: # 如果艺术家为空只使用歌曲名 new_name_without_ext title new_filename f{new_name_without_ext}{ext} new_file_path os.path.join(self.directory, new_filename) # 避免重复如果新文件名已存在添加数字后缀 counter 1 original_new_file_path new_file_path while os.path.exists(new_file_path) and new_file_path ! file_path: new_name_without_ext f{new_name_without_ext} ({counter}) new_filename f{new_name_without_ext}{ext} new_file_path os.path.join(self.directory, new_filename) counter 1 rename_plan.append({ old_path: file_path, new_path: new_file_path, old_name: filename, new_name: new_filename, artist: artist, title: title }) # 执行或打印计划 if dry_run: print( * 60) print(重命名预演dry-run模式以下是将要执行的操作) print( * 60) for i, plan in enumerate(rename_plan, 1): print(f{i:3d}. {plan[old_name]}) print(f - {plan[new_name]}) if plan[artist]: print(f [艺术家: {plan[artist]}, 标题: {plan[title]}]) print() else: print(开始执行重命名操作...) for plan in rename_plan: try: os.rename(plan[old_path], plan[new_path]) print(f✓ 已重命名: {plan[old_name]} - {plan[new_name]}) except Exception as e: print(f✗ 重命名失败 {plan[old_name]}: {e}) print(操作完成。) return rename_plan4.3 创建主程序入口主程序负责接收用户输入目录路径并协调整个流程。# main.py import os import sys from rename_engine import VideoRenamer def main(): print(视频文件智能重命名工具) print(- * 40) # 获取要处理的目录 if len(sys.argv) 1: target_dir sys.argv[1] else: target_dir input(请输入要处理的视频文件目录路径直接回车则使用当前目录: ).strip() if not target_dir: target_dir os.getcwd() # 检查目录是否存在 if not os.path.isdir(target_dir): print(f错误目录 {target_dir} 不存在。) sys.exit(1) # 初始化重命名器 try: renamer VideoRenamer(target_dir) except ValueError as e: print(e) sys.exit(1) print(f\n正在扫描目录: {target_dir}) print(识别视频文件扩展名:, , .join(sorted(renamer._VideoRenamer__VIDEO_EXTENSIONS))) # 注意这里直接访问了类的“私有”属性实际中应通过方法或公共属性暴露。 # 为简化示例我们临时修改一下 rename_engine.py将 VIDEO_EXTENSIONS 作为实例属性。 # 我们在下面的“代码调整说明”中修正。 # 首先进行预演 print(\n *60) print(第一步预演模式Dry Run) print(*60) rename_plan renamer.analyze_directory(dry_runTrue) if not rename_plan: print(未找到可处理的视频文件。) return # 询问用户是否继续 print(\n *60) response input(是否执行以上重命名操作(y/N): ).strip().lower() if response y: print(\n *60) print(第二步执行重命名) print(*60) renamer.analyze_directory(dry_runFalse) print(\n所有操作已完成。建议您检查重命名结果。) else: print(操作已取消。) if __name__ __main__: main()代码调整说明为了让VIDEO_EXTENSIONS在主程序中可访问我们需要对rename_engine.py中的VideoRenamer类做一个小调整# 在 rename_engine.py 的 VideoRenamer 类 __init__ 方法中添加 self.video_extensions VIDEO_EXTENSIONS然后在main.py中将renamer._VideoRenamer__VIDEO_EXTENSIONS替换为renamer.video_extensions。4.4 运行与验证准备测试目录创建一个测试文件夹放入几个命名不规范的文件例如【CORTIS】高清4K完整版 251214 MIC DROP (COVER) - CORTIS MARTIN 横版4K.mp4Awesome Concert - 2025 Live Full HD - My Song.mp4[Official] 歌曲名 - 歌手名 1080p.mkv运行脚本cd /path/to/your/video_renamer python main.py /path/to/your/test_folder或者直接运行python main.py然后输入路径。查看预演结果脚本会首先打印出计划的重命名操作类似于1. 【CORTIS】高清4K完整版 251214 MIC DROP (COVER) - CORTIS MARTIN 横版4K.mp4 - CORTIS MARTIN - MIC DROP.mp4 [艺术家: CORTIS MARTIN, 标题: MIC DROP]确认并执行输入y确认后脚本将执行实际的重命名操作。5. 常见问题与排查思路在实际使用中你可能会遇到以下问题问题现象可能原因解决思路脚本运行后无任何输出提示“未找到可处理的视频文件”。1. 目录路径错误。2. 目录中没有脚本支持扩展名.mp4,.mkv等的文件。3.VIDEO_EXTENSIONS配置未包含你的文件类型。1. 检查输入的目录路径是否正确。2. 确认目录中存在视频文件。3. 在config.py的VIDEO_EXTENSIONS集合中添加你的文件扩展名如.m4v,.ts。重命名后文件名变成了乱码或包含奇怪字符。原始文件名编码与系统编码不匹配常见于Windows。Python 3 默认使用 UTF-8但某些系统文件名可能是 GBK 编码。尝试在脚本开头添加# -*- coding: utf-8 -*-或在读取文件名时处理编码异常。对于复杂情况可以考虑使用os.fsencode/os.fsdecode。解析错误歌手和歌曲名位置反了或未能正确分割。文件名格式不符合脚本预设的“... - ...”分隔模式或分隔符不唯一。1. 调整_parse_artist_and_title方法中的分割逻辑例如尝试按第一个-分割或使用其他分隔符如_。2. 在config.py的REMOVE_PATTERNS中添加更精确的规则先去除更多噪音让核心部分更清晰。3. 考虑使用更复杂的启发式方法如判断哪部分更可能包含常见歌手名或歌曲名词汇。误删了文件名中的重要部分如歌曲名中的数字。REMOVE_PATTERNS中的正则表达式过于宽泛。例如r[0-9]{6}会删除任何6位数字。1. 仔细审查REMOVE_PATTERNS列表禁用或修改过于激进的规则。2. 可以改为匹配特定位置的数字如r\b[0-9]{6}\b匹配单词边界的6位数字。3.强烈建议在正式批量处理前先在一个包含各种样例的测试目录上运行预演模式dry_runTrue仔细检查输出。重命名时因文件名已存在而失败或产生覆盖。脚本生成的新文件名在目标目录中已存在。脚本中已包含简单的防重复逻辑添加数字后缀。如果仍出现问题检查_parse_artist_and_title函数是否对不同的原始文件产生了完全相同的新文件名。可以增加更唯一的标识符如保留原文件的部分哈希值。6. 最佳实践与工程建议将这个简单脚本工程化可以使其更健壮、易用和可维护。日志记录替代print语句使用logging模块记录信息、警告和错误便于后续排查。import logging logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) logger logging.getLogger(__name__)配置文件外部化将REMOVE_PATTERNS和FILENAME_TEMPLATE放在一个独立的配置文件如config.yaml或config.json中无需修改代码即可调整规则。# config.yaml remove_patterns: - 【.*?】 - \[.*?\] - 高清[0-9]*K? filename_template: {artist} - {title} video_extensions: - .mp4 - .mkv单元测试为文件名解析函数编写单元测试确保规则修改后不会破坏现有功能。# test_renamer.py import unittest from rename_engine import VideoRenamer class TestVideoRenamer(unittest.TestCase): def test_clean_filename(self): renamer VideoRenamer(.) result renamer._clean_filename(【TEST】高清4K完整版 歌曲) self.assertEqual(result, 歌曲) if __name__ __main__: unittest.main()递归处理扩展脚本功能使其可以递归处理子目录下的所有视频文件。备份机制在执行重命名前可以选择将原始文件名列表保存到一个日志文件或创建一个备份目录以便随时回滚。图形界面GUI对于非技术用户可以使用tkinter、PyQt或Gooey库包装一个简单的图形界面让用户通过点击选择目录、预览和确认。元数据读取作为高级功能可以集成mutagen音频或hachoir视频等库尝试从文件本身的元数据如ID3标签、MP4元数据中读取歌手和标题这比解析文件名更准确。通过遵循这些最佳实践你可以将一个快速脚本逐步打磨成一个可靠的工具甚至是一个分享给他人使用的小型开源项目。核心思想是先让基础流程跑通再通过迭代增加鲁棒性和功能。