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。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大飞哥软件自习室

希望支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值