Как я могу установить текстовое значение в соответствии с позицией

У меня есть несколько файлов в папке; для каждого файла мне нужно проанализировать его имя в соответствии с определенным форматом. Имена файлов могут быть примерно такими: .\dir1\value1-value2-value3-2.45.13.EXT.\dir1\value1-value2-value4-value5-1.17.04.EXT Вкратце, формат каждого файла мне нужен:

  1. Удалить путь отношения
  2. Удалите первые 2 слова, включая дефис.
  3. Удалите расширение файла.
  4. Разделите оставшиеся на 2 текстовых значения: одно — оставшийся текст без цифр, а второе — оставшиеся числа. Итак, вывод для двух имен файлов должен быть:
| value3 | 2.45.13 |
| value4-value5 | 1.17.04 |

Я попробовал следующий код:

@echo off
setlocal enabledelayedexpansion

for %%p in (
    .\dir1\*.EXT
) do (
    rem This is the full name of the file (relative path + file extension )
    set "relationFileName=%%p"

    rem This is the full name of the file without its relative path
    for %%f in ("!relationFileName!") do set filename=%%~nxf
    rem Removing the file extension
    set "stripped_file=!filename:~0,-4!"

    rem Getting the length of the filename - function is located below
    call :strlen filename_length stripped_file 
    rem echo file=!stripped_file!(!filename_length!^)

    set "delimiter=-"

    rem Iterate over the string from the end to the beginning
    for /l %%i in (0, 1, !filename_length!) do (
    set "index=%%i"
    set char=!stripped_file:~%%i,1!
    rem echo !stripped_file![!index!] = !char!
    if "!char!"= = "!delimiter!" set lastIndex=!index!

    )
    set /a nextIndex=lastIndex + 1
    rem reducing the prefix of `value1-value2-` which we don't want to print out.
    set "prefixLength=14"
    set /a packageNameLength = lastIndex - prefixLength

    rem breaking the filename where the last hyphen character was found
    set packageName=!stripped_file:~%prefixLength%,%packageNameLength%!
    set packageVersion=!stripped_file:~%nextIndex%!

    echo ^| !packageName! ^| !packageVersion! ^|
)

endlocal

REM ********* function *****************************
:strlen <resultVar> <stringVar>
(   
    setlocal EnableDelayedExpansion
    (set^ tmp=!%~2!)
    if defined tmp (
        set "len=1"
        for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
            if "!tmp:~%%P,1!" NEQ "" ( 
                set /a "len+=%%P"
                set "tmp=!tmp:~%%P!"
            )
        )
    ) ELSE (
        set len=0
    )
)

Результат, который я получаю:

| | value1-value2-value3-2.45.13 |
| | value1-value2-value4-value5-1.17.04 |

Проблема в том, что две строки, в которых хранится позиция, в которой текст должен быть разделен, не оцениваются в команде set (которая разбивает текст). В коде вы можете видеть, что для prefixLength, packageNameLength и nextIndex их значения не оцениваются в двух командах установки:

    set packageName=!stripped_file:~%prefixLength%,%packageNameLength%!
    set packageVersion=!stripped_file:~%nextIndex%!

На всякий случай он выводит правильные значения, когда я повторяю эти переменные (prefixLength, packageNameLength и nextIndex). Это также работает правильно, когда я жестко кодирую значения непосредственно в команде set. Но когда я помещаю эти переменные в команду set, они не работают. Кто-нибудь знает, как я могу это исправить?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
63
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я предпочитаю избегать ADFNPSTXZ (в любом случае) в качестве метапеременных (переменных управления циклом). ADFNPSTXZ также являются модификаторами метапеременных, что может привести к трудно обнаруживаемым ошибкам. (См. for/f в приглашении к документации)

@ECHO Off
SETLOCAL enabledelayedexpansion

:: for testing, a set of filenames

SET "filenames=.\dir1\value1-value2-value3-2.45.13.EXT .\dir1\value1-value2-value4-value5-1.17.04.EXT"

FOR %%e IN (%filenames%) DO (
 FOR /f "tokens=2,* delims=-" %%b IN ("%%~ne") DO (
  rem %%~ne removes the extension & relpath. %%c has the first 2 values removed
  SET "remainder=%%c"
  SET "remainderelements=!remainder:-= !"
  FOR %%o IN (!remainderelements!) DO SET "numpart=%%o"&SET "valuepart=!remainder:-%%o=!"
  ECHO %%e --^> !valuepart! + !numpart!
 )
)
GOTO :EOF

Учитывая, что %%e содержит имя файла, например. .\dir1\value1-value2-value3-2.45.13.EXT,

%%~ne будет строкой, содержащей просто часть name строки, т.е. value1-value2-value3-2.45.13 (см. for /? в подсказке для docco). [исправлены комментарии к процедуре REM]

for /f затем маркирует эту строку (заключенную в кавычки без подстановочных знаков), используя - в качестве разделителя, чтобы
токен 1 содержит value1
токен 2 содержит value2
токен * содержит value3-2.45.13 (остаток строки)

Поскольку токены 2 и * выбраны, токен 2 присваивается %%b (выбранной метапеременной), а токен *%%c (следующая алфавитная переменная).

Затем remainder присваивается value3-2.45.13, поскольку %%c не может быть подстрокой.

remainderelements затем присваивается value3 2.45.13 путем замены каждого - на пробел. (см. set /? из подсказки для docco)

%%o затем поочередно устанавливается на value3 и 2.45.13, поскольку remainderelements содержит простой список, разделенный пробелами.

numpart устанавливается для каждого элемента в этом списке по очереди, поэтому он остается установленным для последнего элемента 2.45.13, когда цикл заканчивается.

valuepart аналогично устанавливается значение remainder (value3-2.45.13) с - + последним элементом, 2.45.13 заменяется ничем на последней итерации цикла for %%o.

Бинго!

Ух ты... Я удивлен, увидев такой короткий ответ, который тоже работает :). Можете ли вы объяснить мне немного об этом? Например, как получается, что из %%C удалены относительный путь и первые два значения?

Avraham Cohen 23.07.2024 13:14

Ох! будь немного осторожнее! %%c и %%C — это две разные вещи — единственный случай, когда синтаксис пакетного языка различается из-за регистра (о котором я знаю)

Magoo 23.07.2024 18:30

Другой подход:

@echo off
setlocal EnableDelayedExpansion

rem Create a file list for testing
set "filenames=.\dir1\value1-value2-value3-2.45.13.EXT .\dir1\value1-value2-value4-value5-1.17.04.EXT"

rem Process all filenames: call :split subroutine with file name only
for %%f in (%filenames%) do call :split "%%~Nf"
goto :EOF


rem Get from third to last-but-one hypen-separated elements ("head") and last element

:split
set "list=%~1"  &  set "head = "  &  set "i=0"
set "last=%list:- = " & set /A i+=1 & (if !i! geq 3 set "head=!head!-!last!") & set "last=%"
echo ^| %head:~1% ^| %last% ^|

В этом методе эффективно используется двойная обработка, которая происходит, когда список элементов %заменяется% выражением, которое включает расширение !delayed! Самый простой способ понять, что происходит, — это поместить команду ECHO ON в подпрограмму :split и внимательно просмотреть исполняемый код...

Дополнительное объяснение дано в комментариях ниже этот ответ, а первоисточник этого метода приведен в ссылке в таком ответе.

Другие вопросы по теме