代码之家  ›  专栏  ›  技术社区  ›  anthony

使用regex重命名批处理文件以匹配4位年份

  •  2
  • anthony  · 技术社区  · 6 年前

    在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 回复  |  直到 6 年前
        1
  •  1
  •   Mofi    6 年前

    我使用了20多年的Total Commander(共享软件)来完成文件/文件夹重命名任务,通过它内置的多重重命名工具,只需点击几下就可以轻松地重命名文件和文件夹,在真正运行多重重命名之前可以查看结果,甚至在完成多重重命名后还支持撤消。实际上,几乎所有的文件管理任务都使用totalcommander。

    但是,为这个非常特殊的文件重命名任务开发代码是很有趣的,因为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
    

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

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

    目录 斯特德尔 到设备 努尔 具有 2>nul .

    输出的文件名 目录 重定向为 | 处理 标准 它使用两个正则表达式解释的搜索字符串搜索范围内的四位数字,并区分大小写 1980 1999 2000 2029

    FINDSTR公司 也解释了 ¹ ² ³ [0-9] [0123456789] FINDSTR公司 文章 SS64 - FINDSTR What are the undocumented features and limitations of the Windows FINDSTR command?

    FINDSTR公司 输出范围内包含四位数字的所有文件名 1980 2029 标准 后台命令进程。

    Using Command Redirection Operators 为了解释 2>数字 | > | 必须用插入符号转义 ^ 当Windows命令解释器在执行命令之前处理此命令行时,要解释为文字字符的命令行 执行嵌入的 dir 命令行中的一个单独的命令进程在后台启动。

    捕获这些行并逐行处理它们。选项的默认值 eol= (行尾)是分号,所以 将忽略以分号开头的所有文件名。因为这个原因 eol=|

    为了 默认情况下,将在空格/制表符上拆分每个文件名,并仅将第一个子字符串(标记)分配给指定的循环变量 I delims= 它定义了一个空的分隔符列表。 tokens=* 与此不同,这将导致从文件名中删除前导空格。文件名可以以一个或多个空格开头,尽管这很不寻常。

    !

    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?