Как удалить переменную строку из набора других, более длинных строк? - PullRequest
1 голос
/ 12 октября 2019

Справочная информация: Каталог c:\documents содержит файлы .doc и .xls от разных людей. Где-то в имени файла указаны инициалы, чтобы определить, кто редактировал файл. Каждое имя файла может иметь один или несколько начальных наборов. В этот раз меня интересуют только файлы .doc. Поперечное сечение этого каталога выглядит следующим образом:

depot.inventory.20180921.[CMP]-[OxA](DOT)-(TTR).edited.doc
rack_location_(IIY)collected.2018.11.24.edit[UTS]_{POM}.doc

Список можно продолжать и продолжать для сотен файлов. Я хочу сгенерировать копию этих файлов без инициалов редактора и поместить их в каталог с именем c:\uniform.

Константы здесь: каждый набор инициалов состоит из 3 букв длиной и может быть как верхним, так и нижнимдело и заключено в какие-то скобки. В любой момент у меня есть список инициалов редактора в файле, один набор на строчный формат, такой как:

CMP
OXA
TTR
DOT
UTS
IIY
POM

Файл имеет около 100-150 имен в любой данный день.

До сих пор я выяснил, как удалить один набор инициалов из всех файлов .doc следующим образом:

for /R "C:\documents" %%f in (*.doc) do (
    call :Sub %%~nf
)

:Sub
set str=%*
set str=%str:[DOT]=%
echo %str%

Здесь, в этом сегменте кода, я поставил [DOT] в качестве примера. Я хочу сделать строку [DOT] переменной и прочитать ее из файла инициалов редактора. Тем не менее, это необходимо для каждого файла документа много раз.

Так что моя пакетная программа будет зацикливать все * .doc файлы в исходной директории, для каждого файла она будет проходить через цикл 100-150присваивает имена и удаляет эти строки, формирует новое имя файла и копирует старый файл из исходного каталога в целевой каталог с новым именем файла, которое является инициалами редактора, исключенными из версии исходного имени файла.

Какя могу сделать второй цикл?

Я озадачен синтаксисом.

Ответы [ 3 ]

0 голосов
/ 13 октября 2019

В этом решении используется регулярное выражение в PowerShell. Если вы используете поддерживаемую систему Windows, она будет иметь PowerShell. Это предполагает, что никто не использует ВЕРТИКАЛЬНУЮ ЛИНИЮ как часть своих инициалов или в качестве скобки вокруг инициалов. Измените $DestinationDir на ваш выбор.

Если вы уверены, что файлы будут переименованы правильно, удалите -WhatIf из команды Rename-Item.

=== Rename-Initials.ps1

$SourceDir = 'C:\src\t\reninitials'
$DestinationDir = 'C:\src\t\reninitials\uniform'
$Editors = (Get-Content -Path $(Join-Path -Path $SourceDir -ChildPath 'Editors.txt')) -join '|'
$OpeningBrackets = @('\[', '\(', '{') -join '|'
$ClosingBrackets = @('\]', '\)', '}') -join '|'
$Regex = '(' + $OpeningBrackets + ')(' + $Editors + ')(' + $ClosingBrackets + ')'
$FileTypes = @('*.doc', '*.xls')

foreach ($FileType in $FileTypes) {
    Get-ChildItem -Path $SourceDir -File -Recurse -Filter $FileType |
        ForEach-Object {
            if ($_.Name -match $Regex) {
                $NewName = $_.Name -replace $Regex,''
                Move-Item -LiteralPath $_.FullName `
                    -Destination $(Join-Path -Path $DestinationDir -ChildPath $NewName) -WhatIf
            }
        }
}

Если необходимо вызвать его из оболочки cmd.exe:

powershell -NoLogo -NoProfile -File "Rename-Initials.ps1"
0 голосов
/ 17 октября 2019

Задача, которую вы пытаетесь выполнить, не так тривиальна, особенно когда вы не хотите оставлять последовательности разделителей, такие как точки, дефисы, подчеркивания и т. Д., После удаления частей строки в скобках.

Вот скрипт, который удаляет инициалы известных редакторов в скобках (предопределенные в файле списка initials.txt в текущем каталоге) один за другим;если два соседних разделителя (например, ., -, _, а также ,, ;, %) остались бы позади, первый удаляется;если такого не было бы, вставляется тот, который определен первым (.). Необязательно, потенциальный хвост, состоящий из известного суффикса (например, edited или edit, как определено в сценарии) и предшествующего разделителя, также удаляется. Так что это код, включая некоторые пояснительные rem замечания:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_ROOT=C:\documents" & rem // (root directory; `.` is current, `%~dp0.` is script's parent)
set "_DEST=C:\uniform"   & rem // (destination directory)
set "_OVER="             & rem // (set this to `|` to overwrite existing files, or else to ``)
set "_LIST=initials.txt" & rem // (text file containing list of editors' initials, one per line)
set _MASKS="*.doc" "*.xls" & rem // (list of file patterns to process)
(set _LF=^
%= blank line =%
) & rem // (line-break)
set _PAREN=( )^%_LF%%_LF%[ ]^%_LF%%_LF%{ } & rem // (list of pairs of parentheses)
set _SEPAR=. - _ "," ";" %% & rem // (list of separators; do not use `=`, `~`, `!`, `^`)
set _TAILS="edited" "edit"  & rem // (optional list of suffixes to remove; may be empty)

rem // Change into root (source) directory:
pushd "%_ROOT%" && (
    rem // Iterate through all matching files:
    for %%F in (%_MASKS%) do (
        rem // Store full name of current file:
        set "FILE=%%~F" & set "NAME=%%~nxF"
        rem // Toggle delayed expansion to avoid trouble with `!`:
        setlocal EnableDelayedExpansion
        rem // Loop over the list of initials:
        for /F "usebackq delims= eol=|" %%E in ("%_LIST%") do (
            rem // Loop over trailing separators:
            for %%J in (. !_SEPAR! "") do (
                rem // Loop over leading separators:
                for %%I in (!_SEPAR! "") do (
                    rem // Loop over pairs of parentheses:
                    for /F "tokens=1,2" %%K in ("!_PAREN!") do (
                        rem // Conditionally remove parenthesised text from file name:
                        if not "%%~J"=="" (
                            set "NAME=!NAME:%%~I%%K%%E%%L%%~J=%%~J!"
                        ) else if not "%%~I"=="" (
                            set "NAME=!NAME:%%~I%%K%%E%%L%%~J=%%~I!"
                        ) else if defined _SEPAR (
                            set "NAME=!NAME:%%~I%%K%%E%%L%%~J=%_SEPAR:~,1%!"
                        ) else (
                            set "NAME=!NAME:%%~I%%K%%E%%L%%~J=.!"
                        )
                    )
                )
            )
        )
        rem // Process optional list of suffixes:
        if defined _TAILS (
            rem // Use `for /F` loop to split file name into base name and extension:
            for /F "delims= eol=|" %%N in (""!NAME!"") do (
                endlocal
                rem // Store file name components:
                set "NAME=%%~nxN" & set "EXT=%%~xN" & set "TEST=%%~nN|"
                setlocal EnableDelayedExpansion
                rem // Loop over suffixes:
                for %%M in (!_TAILS!) do (
                    rem // Loop over separators:
                    for %%J in (!_SEPAR!) do (
                        rem // Remove found suffix from base name:
                        if not "!TEST!"=="!TEST:%%~J%%~M|=!" (
                            set "NAME=!TEST:%%~J%%~M|=!!EXT!"
                        )
                    )
                )
            )
        )
        rem // Actually copy file to destination with the newly built name:
        if not exist "!_DEST!\!NAME!!_OVER!" (
            ECHO copy /Y "!FILE!" "!_DEST!\!NAME!"
        )
        endlocal
    )
    popd
)

endlocal
exit /B

Настройте точное поведение в разделе Define constants here: вверху.

После проверки вывода удалитекоманда ECHO в верхнем регистре для фактического копирования файлов;чтобы подавить многочисленные строки 1 file(s) copied., возвращаемые командой copy, замените вместо этого ECHO на > nul.

0 голосов
/ 12 октября 2019

Вот комментированный пакетный файл для этой необычной задачи копирования файла.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=C:\documents"
set "DestinationFolder=C:\uniform"

rem Is there no *.doc file to process in source directory?
if not exist "%SourceFolder%\*.doc" goto :EOF

rem Do nothing if the text file with editors' initials
rem does not exist in the batch file directory.
if not exist "%~dp0EditorsInitials.txt" goto :EOF

rem Create the destination directory on not already existing
rem and veriy the real existence of the destination directory.
md "%DestinationFolder%" 2>nul
if not exist "%DestinationFolder%\" goto :EOF

rem Read the editors' initials from text file and create a space separated
rem list of them assigned to the environment variable EditorsInitials.

setlocal EnableDelayedExpansion
set "EditorsInitials="
for /F "usebackq" %%I in ("%~dp0EditorsInitials.txt") do set "EditorsInitials=!EditorsInitials! %%~I"
endlocal & set "EditorsInitials=%EditorsInitials:~1%"

rem For each non-hidden *.doc file in source directory get file name with
rem file extension and with path if there is one specified left to *.doc
rem and assign it to the environment variable FullFileName. The file name
rem only is assigned to the environment variable FileName. Then delayed
rem environment variable expansion is enabled again for running two nested
rem loops which runs case-insensitive string substitutions on the file name
rem string value to remove the editors' initials from the file name. Next
rem one more loop is used to remove also .edited and .edit from file name.
rem The current *.doc file is finally copied with cleaned file name to
rem the configured destination directory. A date in file name remains.

for %%I in ("%SourceFolder%\*.doc") do (
    set "FullFileName=%%I"
    set "FileName=%%~nI"
    setlocal EnableDelayedExpansion
    for %%J in (%EditorsInitials%) do for %%K in ("-" "." "_" "") do (
        set "FileName=!FileName:%%~K[%%J]=!"
        set "FileName=!FileName:%%~K(%%J)=!"
        set "FileName=!FileName:%%~K{%%J}=!"
    )
    for %%J in (".edited" ".edit") do set "FileName=!FileName:%%~J=!"
    copy "!FullFileName!" "%DestinationFolder%\!FileName!%%~xI" >nul
    endlocal
)
endlocal

Этот пакетный файл выполняет команду copy с файлом EditorsInitials.txt в каталоге пакетного файла, содержащего опубликованный списокинициалы редакторов для двух примеров * .doc файлов с аргументами:

"C:\documents\depot.inventory.20180921.[CMP]-[OxA](DOT)-(TTR).edited.doc" "C:\uniform\depot.inventory.20180921.doc"
"C:\documents\rack_location_(IIY)collected.2018.11.24.edit[UTS]_{POM}.doc" "C:\uniform\rack_locationcollected.2018.11.24.doc"

Для понимания используемых команд и их работы откройте окно командной строки, выполните там следующие команды и полностью прочитайте всестраницы справки для каждой команды отображаются очень внимательно.

  • call /? ... объясняет %~dp0 ... диск и путь аргумента 0, который всегда является полным путем к каталогу, содержащему этот пакетный файлзаканчивая обратной косой чертой.
  • copy /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • md /?
  • rem /?
  • set /?
  • setlocal /?

См. Также статью Microsoft о Использование операторов перенаправления команд для объяснения >nul и 2>nul.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...