Пакетное переименование файла с использованием регулярных выражений для соответствия 4-значному году - PullRequest
0 голосов
/ 01 сентября 2018

В пакетном файле 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 голосов
/ 01 сентября 2018

Более 20 лет я использую Total Commander (условно-бесплатное программное обеспечение) для задач переименования файлов / папок, что позволяет с помощью встроенного инструмента многократного переименования легко переименовывать файлы и папки с помощью всего нескольких щелчков мыши, по которым результаты могут быть просмотренным до того, как вы действительно запустите многократное переименование, и которое даже поддерживает отмену после выполнения многократного переименования. Ну, на самом деле я использую 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 выводит с использованными параметрами все имена не скрытых файлов в текущем каталоге только с именем файла + расширением и без пути к файлу. Вывод сообщения об ошибке, если в текущем каталоге отсутствует скрытый файл, подавляется путем перенаправления его из дескриптора STDERR на устройство NUL с 2>nul.

Имена файлов, выводимые с помощью DIR , перенаправляются с помощью | для обработки STDIN команды FINDSTR , которая выполняет поиск с учетом регистра двумя интерпретированными регулярными выражениями поиска строки из четырех цифр в диапазоне от 1980 до 1999 или в диапазоне от 2000 до 2029. Проверка не выполняется, если совпадение четырехзначного числа является частью большего числа, такого как 12000 или 19975. И проверка не выполняется, если вокруг четырехзначного числа уже есть круглые скобки.

FINDSTR также интерпретирует ¹, ², ³ как цифру при использовании [0-9], что является причиной использования [0123456789] для реального совпадения только с любым из этих 10-значных символов. Пожалуйста, ознакомьтесь с более подробной информацией о FINDSTR статьях SS64 - FINDSTR и Каковы недокументированные функции и ограничения команды Windows FINDSTR?

FINDSTR выводит все имена файлов, содержащие четыре цифры в диапазоне от 1980 до 2029 для обработки STDOUT процесса фоновой команды.

Пожалуйста, прочитайте статью Microsoft о Использование операторов перенаправления команд для объяснения 2>nul и |. Операторы перенаправления > и | должны быть экранированы с помощью символа вставки ^ в FOR , чтобы интерпретировать их как буквенные символы, когда интерпретатор команд Windows обрабатывает эту командную строку перед выполнением команды FOR , который выполняет встроенную командную строку dir в отдельном командном процессе, запущенном в фоновом режиме.

FOR захватывает эти строки и обрабатывает их построчно. По умолчанию для опции eol= (конец строки) используется точка с запятой, поэтому FOR будет игнорировать все имена файлов, начинающиеся с точки с запятой. По этой причине eol=| указано, поскольку вертикальная черта не может использоваться в имени файла, и поэтому все захваченные имена файлов обрабатываются с помощью FOR .

FOR будет разделять каждое имя файла по пробелам / табуляциям по умолчанию и назначать только первую подстроку (токен) указанной переменной цикла 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 /?

См. Также Куда возвращается GOTO: EOF?

PS: Имена файлов с ( или ) в имени делают обработку их с помощью пакетного файла очень часто более сложной, так как в этом случае имя файла всегда должно быть заключено в двойные кавычки, как для имен файлов, содержащих пробел потому что ( и ) также имеют специальное значение для командного процессора Windows cmd.exe, как это видно из кода выше. См. Также Как интерпретирует сценарии интерпретатора команд Windows (CMD.EXE)?

...