使用正则表达式重命名批处理文件以匹配4位数字的年份

时间:2018-09-01 06:29:50

标签: batch-file findstr

在Windows批处理文件中,我想通过简单地将年份字符串包装在括号中来重命名文件名中包含4位数字的年份(例如:“ 1999”)。示例:

home video 1998.avi
home vid 1987.mov
home_video (2002).avi

将成为

home video (1998).avi
home vid (1987).mov
home_video (2002).avi

请注意,如果已经将其括在括号中,则我不希望将它们加倍。

到目前为止,我只能用以下代码匹配包含年份字符串的文件名:

@echo off
REM Match file names with 4-digit year
setlocal enableDelayedExpansion

for /f "tokens=1* delims=" %%A in (
  'dir /B "*"^|findstr "[1-2][0-9][0-9][0-9]" '
) do @echo %%A

pause
REM Now what?

所以我可以输出匹配文件名的列表,但是从那里我不知道如何定位findstr匹配的分组字符,以便将完整文件名解析为我认为需要的3个块:子字符串在匹配的组之前,组本身以及该组之后的子字符串。

在批处理文件中可以吗?

1 个答案:

答案 0 :(得分:1)

我使用Total Commander(共享软件)已有20多年了,用于文件/文件夹重命名任务,这使它具有内置的多重重命名工具,只需单击几下即可轻松重命名文件和文件夹,结果可以在真正运行多重重命名之前进行查看,甚至可以在执行多重重命名后支持undo。好吧,实际上我使用Total Commander几乎完成了所有文件管理任务。

但是为这种非常特殊的文件重命名任务开发代码很有趣,但由于Windows命令处理器没有针对此类任务而设计,因此它具有所有限制。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /R /C:"19[89][0123456789]" /C:"20[012][0123456789]"') do call :RenameFile "%%I"
endlocal
goto :EOF

:RenameFile
set "FileName=%~n1"
setlocal EnableDelayedExpansion
set "Year=1980"

:YearLoop
set "NewName=!FileName:%Year%=(%Year%)!"
if "!NewName!" == "!FileName!" (
    if %Year% == 2029 goto ExitSub
    set /A Year+=1
    goto YearLoop
)
if "!FileName:(%Year%)=!" == "!FileName!" ren "%~1" "!NewName!%~x1"

:ExitSub
endlocal
goto :EOF

FOR 在以cmd.exe /C在后​​台启动的单独命令过程中执行以下命令行:

dir /A-D-H /B 2>nul | C:\Windows\System32\findstr.exe /R /C:"19[89][0123456789]" /C:"20[012][0123456789]"

DIR 通过使用的选项输出当前目录中所有非隐藏文件的名称,仅包含文件名+扩展名,而没有文件路径。通过使用2>nul将文件从句柄 STDERR 重定向到设备 NUL ,可以抑制当前目录不包含任何非隐藏文件的错误消息输出。 / p>

DIR 输出的文件名使用|重定向,以处理命令 FINDSTR STDIN ,该命令搜索区分大小写两个正则表达式解释的搜索字符串,其范围为1980199920002029范围内的四个数字。不会检查四位数的匹配是否是较大数字(例如12000或19975)的一部分。也不会检查四位数的周围是否已经有圆括号。

FINDSTR 还将¹²³解释为使用[0-9]的数字,这就是使用[0123456789]的原因真正只匹配那些10位数字字符中的任何一个。请阅读有关 FINDSTR 文章SS64 - FINDSTRWhat are the undocumented features and limitations of the Windows FINDSTR command?

的更多详细信息

FINDSTR 输出所有在19802029范围内包含四位数的文件名,以处理后台命令过程的 STDOUT

请阅读有关Using Command Redirection Operators的Microsoft文章,以获取2>nul|的解释。重定向操作符>|必须用 FOR 命令行上的脱字符号^进行转义,以在Windows命令解释器处理此命令行时将其解释为原义字符。在执行命令 FOR 之前,该命令将在后台启动的单独命令进程中执行嵌入的dir命令行。

FOR 捕获这些行并逐行处理它们。选项eol=(行尾)的默认值是分号,因此 FOR 将忽略所有以分号开头的文件名。因此,指定eol=|是因为文件名中不能使用竖线,因此所有捕获的文件名均由 FOR 处理。

FOR 默认情况下会在空格/制表符上拆分每个文件名,并且仅将第一个子字符串(令牌)分配给指定的循环变量I。通过使用delims=(它定义了一个空的定界符列表)来禁用此拆分行为。 tokens=*与此不同,这会导致从文件名中删除前导空格。文件名可以以一个或多个空格开头,尽管这种情况很不常见。

文件名还可以包含感叹号!,在使用延迟的环境变量扩展时也必须考虑这些感叹号。每个文件名都传递给子例程以进行进一步处理。

使用循环将圆括号中的年份替换为分配给循环变量Year的year的所有实例,直到新文件名与当前文件名不同,因为对搜索字符串而言,替换确实为正。 for /L %%J in (1980,1,2029) do ...未被使用,因为一旦找到正确的文件名年份就无法退出此循环。

在文件名中找到年份后,将检查今年是否尚未嵌入括号中,以避免将名称为home vid (1987).mov的文件重命名为home vid ((1987)).mov。因此,例如home video 1998.avi最终重命名为home video (1998).avi

包含两个具有四个或更多数字的数字的文件名也无法正确处理,因为此代码无法找出该文件名中的年份。

此批处理代码的速度并不是很快,但是它应该可以在列出的限制下使用。

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

  • call /?
  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • goto /?
  • if /?
  • ren /?
  • set /?
  • setlocal /?

另请参阅Where does GOTO :EOF return to?

PS:名称中带有()的文件名使处理批处理文件变得更加困难,因为在这种情况下,文件名必须始终用双引号括起来,例如文件名在Windows代码处理器(中,由于)cmd.exe而包含空格字符也具有特殊含义,如上面的代码所示。另请参见How does the Windows Command Interpreter (CMD.EXE) parse scripts?