python小项目:将带有美国风格日期的文件改名为欧洲风格日期-part文件

python小项目:将带有美国风格日期的文件改名为欧洲风格日期-part文件

假定你的老板用电子邮件发给你上千个文件,文件名包含美国风格的日期

(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 "python小项目:将带有美国风格日期的文件改名为欧洲风格日期-part文件" to "

假定你的老板用电子邮件发给你上千个文件,文件名包含美国风格的日期

(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

168 Python 编程快速上手——让繁琐工作自动化

将连接的字符串保存在名为 euroFilename 的变量中。然后将 amerFilename 中

原来的文件名和新的 euroFilename 变量传递给 shutil.move()函数,将该文件改名。

这个程序将 shutil.move()调用注释掉,代之以打印出将被改名的文件名。先

像这样运行程序,你可以确认文件改名是正确的。然后取消 shutil.move()调用的注

释,再次运行该程序,确实将这些文件改名。

"...' amerFilename, euroFilename))

 #shutil.move(amerFilename, euroFilename) # uncomment after testing

168 Python 编程快速上手——让繁琐工作自动化

将连接的字符串保存在名为 euroFilename 的变量中。然后将 amerFilename 中

原来的文件名和新的 euroFilename 变量传递给 shutil.move()函数,将该文件改名。

这个程序将 shutil.move()调用注释掉,代之以打印出将被改名的文件名。先

像这样运行程序,你可以确认文件改名是正确的。然后取消 shutil.move()调用的注

释,再次运行该程序,确实将这些文件改名。

推荐阅读