- 内容提要
- 作者简介
- 技术评审者简介
- 致谢
- 译者序 会编程的人不一样
- 前言
- 本书的读者对象
- 编码规范
- 什么是编程
- 本书简介
- 下载和安装 Python
- 启动 IDLE
- 如何寻求帮助
- 聪明地提出编程问题
- 小结
- 第一部分 Python 编程基础
- 第1章 Python 基础
- 第2章 控制流
- 第3章 函数
- 第4章 列表
- 第5章 字典和结构化数据
- 第6章 字符串操作
- 第二部分 自动化任务
- 第7章 模式匹配与正则表达式
- 第8章 读写文件
- 第9章 组织文件
- 第10章 调试
- 第11章 从 Web 抓取信息
- 第12章 处理 Excel 电子表格
- 第13章 处理 PDF 和 Word 文档
- 第14章 处理 CSV 文件和 JSON 数据
- 第15章 保持时间、计划任务和启动程序
- 第16章 发送电子邮件和短信
- 第17章 操作图像
- 第18章 用 GUI 自动化控制键盘和鼠标
- 附录A 安装第三方模块
- 附录B 运行程序
- 附录C 习题答案
9.4 项目:将带有美国风格日期的文件改名为欧洲风格日期
假定你的老板用电子邮件发给你上千个文件,文件名包含美国风格的日期(MM-DD-YYYY),需要将它们改名为欧洲风格的日期(DD-MM-YYYY)。手工完成这个无聊的任务可能需要几天时间!让我们写一个程序来完成它。
下面是程序要做的事:
· 检查当前工作目录的所有文件名,寻找美国风格的日期。
· 如果找到,将该文件改名,交换月份和日期的位置,使之成为欧洲风格。
这意味着代码需要做下面的事情:
· 创建一个正则表达式,可以识别美国风格日期的文本模式。
· 调用os.listdir(),找出工作目录中的所有文件。
· 循环遍历每个文件名,利用该正则表达式检查它是否包含日期。
· 如果它包含日期,用shutil.move()对该文件改名。
对于这个项目,打开一个新的文件编辑器窗口,将代码保存为renameDates.py。
第1步:为美国风格的日期创建一个正则表达式
程序的第一部分需要导入必要的模块,并创建一个正则表达式,它能识别MM-DD-YYYY格式的日期。TODO注释将提醒你,这个程序还要写什么。将它们作为TODO,就很容易利用IDLE的Ctrl-F查找功能找到它们。让你的代码看起来像这样:
#! python3 # renameDates.py - Renames filenames with American MM-DD-YYYY date format # to European DD-MM-YYYY. ❶ import shutil, os, re # Create a regex that matches files with the American date format. ❷ datePattern = re.compile(r"""^(.*?) # all text before the date ((0|1)?\d)- # one or two digits for the month ((0|1|2|3)?\d)- # one or two digits for the day ((19|20)\d\d) # four digits for the year (.*?)$ # all text after the date ❸ """, re.VERBOSE) # TODO: Loop over the files in the working directory. # TODO: Skip files without a date. # TODO: Get the different parts of the filename. # TODO: Form the European-style filename. # TODO: Get the full, absolute file paths. # TODO: Rename the files.
通过本章,你知道shutil.move()函数可以用于文件改名:它的参数是要改名的文件名,以及新的文件名。因为这个函数存在于shutil模块中,所以你必须导入该模块❶。
在为这些文件改名之前,需要确定哪些文件要改名。文件名如果包含spam4-4-1984.txt和01-03-2014eggs.zip这样的日期,就应该改名,而文件名不包含日期的应该忽略,诸如littlebrother.epub。
可以用正则表达式来识别该模式。在开始导入re模块后,调用re.compile()创建一个Regex对象❷。传入re.VERBOSE作为第二参数❸,这将在正则表达式字符串中允许空白字符和注释,让它更可读。
正则表达式字符串以^(.*?)开始,匹配文件名开始处、日期出现之前的任何文本。((0|1)?\d)分组匹配月份。第一个数字可以是0或1,所以正则表达式匹配12,作为十二月份,也会匹配02,作为二月份。这个数字也是可选的,所以四月份可以是04或4。日期的分组是((0|1|2|3)?\d),它遵循类似的逻辑。3、03和31是有效的日期数字(是的,这个正则表达式会接受一些无效的日期,诸如4-31-2014、2-29-2013和0-15-2014。日期有许多特例,很容易被遗漏。为了简单,这个程序中的正则表达式已经足够好了)。
虽然1885是一个有效的年份,但你可能只在寻找20世纪和21世纪的年份。这防止了程序不小心匹配非日期的文件名,它们和日期格式类似,诸如10-10-1000.txt。
正则表达式的(.*?)$部分,将匹配日期之后的任何文本。
第2步:识别文件名中的日期部分
接下来,程序将循环遍历os.listdir()返回的文件名字符串列表,用这个正则表达式匹配它们。文件名不包含日期的文件将被忽略。如果文件名包含日期,匹配的文本将保存在几个变量中。用下面的代码代替程序中前3个TODO:
#! python3 # renameDates.py - Renames filenames with American MM-DD-YYYY date format # to European DD-MM-YYYY. --snip-- # Loop over the files in the working directory. for amerFilename in os.listdir('.'): mo = datePattern.search(amerFilename) # Skip files without a date. ❶ if mo == None: ❷ continue ❸ # Get the different parts of the filename. beforePart = mo.group(1) monthPart = mo.group(2) dayPart = mo.group(4) yearPart = mo.group(6) afterPart = mo.group(8) --snip--
如果search()方法返回的Match对象是None❶,那么amerFilename中的文件名不匹配该正则表达式。continue语句❷将跳过循环剩下的部分,转向下一个文件名。
否则,该正则表达式分组匹配的不同字符串,将保存在名为beforePart、monthPart、dayPart、yearPart和afterPar的变量中❸。这些变量中的字符串将在下一步中使用,用于构成欧洲风格的文件名。
为了让分组编号直观,请尝试从头阅读该正则表达式,每遇到一个左括号就计数加一。不要考虑代码,只是写下该正则表达式的框架。这有助于使分组变得直观,例如:
datePattern = re.compile(r"""^(1) # all text before the date (2 (3) )- # one or two digits for the month (4 (5) )- # one or two digits for the day (6 (7) ) # four digits for the year (8)$ # all text after the date """, re.VERBOSE)
这里,编号1至8代表了该正则表达式中的分组。写出该正则表达式的框架,其中只包含括号和分组编号。这让你更清楚地理解所写的正则表达式,然后再转向程序中剩下的部分。
第3步:构成新文件名,并对文件改名
作为最后一步,连接前一步生成的变量中的字符串,得到欧洲风格的日期:日期在月份之前。用下面的代码代替程序中最后3个TODO:
#! python3 # renameDates.py - Renames filenames with American MM-DD-YYYY date format # to European DD-MM-YYYY. --snip-- # Form the European-style filename. ❶ euroFilename = beforePart + dayPart + '-' + monthPart + '-' + yearPart + afterPart # Get the full, absolute file paths. absWorkingDir = os.path.abspath('.') amerFilename = os.path.join(absWorkingDir, amerFilename) euroFilename = os.path.join(absWorkingDir, euroFilename) # Rename the files. ❷ print('Renaming "%s" to "%s"...' % (amerFilename, euroFilename)) ❸ #shutil.move(amerFilename, euroFilename) # uncomment after testing
将连接的字符串保存在名为euroFilename的变量中❶。然后将amerFilename中原来的文件名和新的euroFilename变量传递给shutil.move()函数,将该文件改名❸。
这个程序将shutil.move()调用注释掉,代之以打印出将被改名的文件名❷。先像这样运行程序,你可以确认文件改名是正确的。然后取消shutil.move()调用的注释,再次运行该程序,确实将这些文件改名。
第4步:类似程序的想法
有很多其他的理由,导致你需要对大量的文件改名。
· 为文件名添加前缀,诸如添加spam_,将eggs.txt改名为spam_eggs.txt。
· 将欧洲风格日期的文件改名为美国风格日期。
· 删除文件名中的0,诸如spam0042.txt。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论