I have several files in a folder; for each file, I need to parse its filename according to a specific format.
The filenames can be something like:
.\dir1\value1-value2-value3-2.45.13.EXT
.\dir1\value1-value2-value4-value5-1.17.04.EXT
In short, the format for each file I need:
| value3 | 2.45.13 |
| value4-value5 | 1.17.04 |
I tried the following code:
@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
)
)
The output that I am getting is:
| | value1-value2-value3-2.45.13 |
| | value1-value2-value4-value5-1.17.04 |
The problem is that the 2 lines that stores the position where the text should be split do not evaluate in the set command (that splits the text).
You can see in the code that for prefixLength
, packageNameLength
& nextIndex
, their values are not being evaluated in the 2 set commands:
set packageName=!stripped_file:~%prefixLength%,%packageNameLength%!
set packageVersion=!stripped_file:~%nextIndex%!
Just to be sure, it outputs the correct values when I am echoing these variables (prefixLength
, packageNameLength
& nextIndex
).
It also works correctly when I am hardcoding the values directly into the set command.
But, when I put these variables into the set command, they don't work.
Does anyone know how can I fix this?
I prefer to avoid ADFNPSTXZ (in either case) as metavariables (loop-control variables)
ADFNPSTXZ are also metavariable-modifiers which can lead to difficult-to-find bugs
(See for/f
from the prompt for documentation)
@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
Given that %%e
contains the filename, eg. .\dir1\value1-value2-value3-2.45.13.EXT
,
%%~ne
will be the string containing simply the name
portion of the string, ie value1-value2-value3-2.45.13
(see for /?
from the prompt for docco). [procedure REM comments corrected]
for /f
then tokenises that string (quoted without wildcards) using -
as a delimiter so that
token 1 contains value1
token 2 contains value2
token * contains value3-2.45.13
(the remainder of the string)
Since tokens 2
and *
are selected, token 2
is assigned to %%b
(the chosen metavariable) and token *
to %%c
(next-alphabetical variable)
remainder
is then assigned value3-2.45.13
since %%c
cannot be substringed.
remainderelements
is then assigned value3 2.45.13
by replacing each -
with a space.(see set /? from the prompt for docco)
%%o
is then set to value3
& 2.45.13
in turn, since remainderelements
contains a simple space-separated list.
numpart
is set to each element in that list in turn, so it remains set to the last element, 2.45.13
when the loop ends.
valuepart
similarly is set to the value of remainder
(value3-2.45.13
) with -
+ the last element, 2.45.13
replaced by nothing on the last iteration of the for %%o
loop.
Bingo!