如果存在某些匹配项,则如何使用重新启动的序列重命名文件

时间:2015-12-02 18:37:29

标签: python batch-file file-rename

这个标题没有解释,但我无法快速总结。假设我有这样的文件(全部在同一目录中)......

abc_foo_file1_morestuff.ext
abc_foo_file2_morestuff.ext
efg_goo_file1_morestuff.ext
jkl_zoo_file0_morestuff.ext
jkl_zoo_file1_morestuff.ext
jkl_zoo_file4_morestuff.ext
xyz_roo_file6_morestuff.ext

我希望将它们重命名为:

abc-1.ext
abc-2.ext
efg-1.ext
jkl-1.ext
jkl-2.ext
jkl-3.ext
xyz-1.ext

所以基本上集合中的一些文件(abc,jkl,xyz)被删除了,有些文件被重命名为零,所以它们首先被列出。但是我想重新排序它们从1开始,并且序列中没有任何间隙。

我用Python标记了这个,因为这是我以前尝试过的,但是如果有更简单或更简洁的方法,我就是全力以赴!

3 个答案:

答案 0 :(得分:0)

您可以使用批处理文件执行此操作:

@ECHO OFF
SETLOCAL EnableExtensions EnableDelayedExpansion

REM Process each EXT file in the specified directory.
FOR /F "usebackq tokens=* delims=" %%A IN (`DIR /B /S "C:\Path\To\Files\*.ext"`) DO (

    REM Extract the prefix.
    FOR /F "usebackq tokens=1 delims=_" %%X IN ('%%~nA') DO SET Prefix=%%X

    REM Running tally of each prefix.
    SET /A Count[!Prefix!] += 1

    REM Rename the file using the prefix.
    CALL SET NewName=!Prefix!-%%Count[!Prefix!]%%
    REN "%%A" "!NewName!%%~xA"
)

ENDLOCAL

答案 1 :(得分:0)

我对此问题的一般处理方法如下:

  • 获取要重命名的所有文件的列表
  • 创建起始序列列表
  • 浏览以每个序列更改名称开头的文件列表
  • (可选)对每个序列中的文件列表进行排序

所以,在python中看起来像:

from os import listdir
from os.path import isfile, join, splitext
import shutil
import re

mypath = "./somewhere/"

# this function taken from an answer to http://stackoverflow.com/questions/4836710/does-python-have-a-built-in-function-for-string-natural-sort
def natural_sort_key(s, _nsre=re.compile('([0-9]+)')):
    return [int(text) if text.isdigit() else text.lower()
        for text in re.split(_nsre, s)]

# Get a list of all files in a directory
infiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]

# Create a set of starting sequences
sequences = {splitext(file)[0].split('_')[0] for file in infiles}

# Now go about changing the files
for seq in sequences:
    files = sorted([f for f in infiles if f.startswith(seq)],
                   key=natural_sort_key) # sort the files, if you like
    for idx, file in enumerate(files):
        new_name = seq + '-' + str(idx + 1) + '.' + splitext(file)[1][1:]
        print(file, " -> ", new_name)
        # copy or move
        #shutil.copy2(join(mypath,file), join(mypath,new_name))
        #shutil.move(join(mypath,file), join(mypath,new_name))

答案 2 :(得分:0)

这是一个纯粹的解决方案,可以满足您的所有要求(另请参阅rem条评论):

@echo off

setlocal EnableExtensions

rem definition of temporary file:
set "TEMPFILE=%TMP%\~AlphaNum.tmp"

rem first loop structure for listing the files with `dir`
rem and creating the temporary file for later sorting:
> "%TEMPFILE%" (
    for /F "eol=| tokens=1,2,3,* delims=_" %%I in ('
        dir /B /A:-D "*_*_file*_*.ext"
    ') do (
        rem store different parts of the file name into variables:
        setlocal DisableDelayedExpansion
        set "LINI=%%~I" & rem this is the very first part (prefix)
        set "LINL=%%~J" & rem this is the part left to `file*`
        set "LINM=%%~K" & rem this is the part `file*` (`*` is numeric)
        set "LINR=%%~L" & rem this is the part right to `file*`
        setlocal EnableDelayedExpansion
        rem extract the numeric part of `file*` and pad with leading `0`s;
        rem so the index is now of fixed width (12 figures at most here):
        set "LINN=000000000000!LINM:*file=!" & set "LINN=!LINN:~-12!"
        rem write file name with replaced fixed-width index and without
        rem word `file`, followed by `|`, followed by original file name,
        rem to the temporary file (the `echo` is redirected `>`):
        echo !LINI!_!LINL!_!LINN!_!LINR!^|!LINI!_!LINL!_!LINM!_!LINR!
        endlocal
        endlocal
    )
)

rem second loop structure for reading the temporary file,
rem sorting its lines with `sort`, generating new indexes
rem (sorting the previously built fixed-width indexes as text
rem result in the same order as sorting them as numbers) and
rem building the new file names (original first part + new index):
set "PREV="
for /F "eol=| tokens=2 delims=|" %%I in ('
    sort "%TEMPFILE%"
') do (
    setlocal DisableDelayedExpansion
    rem get the full original file name, and its extension:
    set "FILE=%%~I"
    set "FEXT=%%~xI"
    rem this loop iterates once only and extracts the part before the first `_`:
    for /F "eol=| tokens=1 delims=_" %%X in ("%%~I") do (
        set "CURR=%%~X"
    )
    setlocal EnableDelayedExpansion
    rem if the current prefix equals the previous one, increment the index;
    rem otherwise, reset the index to `1`:
    if /I "!CURR!"=="!PREV!" (
        set /A SNUM+=1
    ) else (
        set /A SNUM=1
    )
    rem remove `ECHO` from the following line to actually rename files:
    ECHO ren "!FILE!" "!CURR!-!SNUM!!FEXT!"
    rem this loop iterates once only and transports the values of
    rem some variable values past the `setlocal`/`endlocal` barrier:
    for /F "tokens=1,* delims=|" %%X in ("!SNUM!|"!CURR!"") do (
        endlocal
        endlocal
        set "SNUM=%%X"
        set "PREV=%%~Y"
    )
)

rem remove `REM` from the following line to delete temporary file:
REM del "%TEMPFILE%"

endlocal

需要切换EnableDelayedExpansionDisableDelayedExpansion才能使脚本对文件名中可能出现的任何特殊字符具有健壮性,例如%!,{{ 1}},()&。在命令提示符下键入^以查找有关延迟变量扩展的简要信息。

这种方法依赖于以下假设:

  • 文件与模式set /?;
  • 匹配
  • 文件名部分*_*_file*_*.ext均不包含*个字符;
  • 单词_后面的索引是最多12位的十进制数字;
  • 第一个和第二个file之间的部分优先于单词_之后关于排序顺序的索引;例如,假设有两个文件fileabc_AAA_file8_*.extabc_BBB_file5_*.ext将重命名为abc_AAA_file8_*.extabc-1.ext将重命名为abc_BBB_file5_*.ext,因为{ {1}}出现在abc-2.ext之前;如果这是所需的行为,请在第一个循环结构中交换AAA命令行:BBB;
  • 新生成的索引未填充前导零;

使用您问题中的示例文件,临时文件包含以下行:

echo