3

I'm trying to find a way to make nested for loops work, but this iteration is different than the most popular results (where an OP is looping through directories, or using a numerical for /l loop, etc.)

Instead, I'm trying to figure out how to make this work:

@echo Off
setlocal enabledelayedexpansion enableextensions


for /f "Tokens=1-7 Delims=_" %%P in ("Testing_This_GREAT_Thing_Of_An_IDEA") do (
  Echo %%P
  For %%a in (P Q R S T U V ) do (
    Call set "term=%%%%%%a"
    Call echo !term!
    Call set term=%%term%%
    Call Echo !term!
    Call set term=%%term%%
    Call Echo !term!
    If not "!term!"=="" Call set word.%%a=%%term%%
    Echo word.%%a = "!word.%%a!"
  )
)
pause
exit /b

Desired output of For %%a in (P Q R S T U V) loop would be to have:

word.P=Testing
word.Q=This
word.R=GREAT
word.S=Thing
word.T=Of
word.U=An
word.V=IDEA

Obviously the following would be as expected for the initial loop, but I cannot get the delayed expansion (I assume) to work as expected. . . .

%%P=Testing
%%Q=This
%%R=GREAT
%%S=Thing
%%T=Of
%%U=An
%%V=IDEA
k1dfr0std
  • 379
  • 1
  • 15
  • For what it is worth, I am able to use a Subroutine/function with the inner `for loop`, calling it using the `parsed Tokens` as arguments and the `Shift` command, but was hoping I could use just the nested `For` Loops instead. – k1dfr0std Dec 11 '22 at 08:25
  • Saving another edit to the question - the current output I get is `%%P` and so forth - just not the expanded variable – k1dfr0std Dec 11 '22 at 08:35
  • As I Ponder this, I thought for SURE I saw this answered somewhere a LONG time ago with the great @dbenham providing valuable insight to the `For` command, but I cannot recall if he determined this kind of iteration was possible or not – k1dfr0std Dec 11 '22 at 08:55
  • 4
    There is a much simpler way to build an array from a list using a delimiter. See: https://www.dostips.com/forum/viewtopic.php?t=6429 – T3RR0R Dec 11 '22 at 09:57
  • I REALLY like this too - great stuff - wonderful find! I believe I could interpret the code from @Aacini (Assuming he's the very one and same here on beloved SO) - to make (by his first example) something along the lines of `set i=1 && set "x=Delimited_String_For_Testing_Purposes" && set "x!i!=%x:_=" & set /A i+=1 & set "x!i!=%"` seeing his is making "o" the Delim. – k1dfr0std Dec 11 '22 at 14:43
  • I must say - I absolutely LOVE it here - I went back again to that post you shared @T3RR0R and there are some INTENSE examples there - thank you again for sharing this! – k1dfr0std Dec 11 '22 at 14:46

3 Answers3

2

No, it's not possible (in a single block).

You try to dynamically access a FOR meta variable, but FOR meta variables are recognized only in the parsing phase, before the code block is executed. An inline call can't help here, because a FOR meta variable isn't detected at all in the second parsing round of a call command.

But you could use a helper function, using the fact that you can access all FOR meta variables in any FOR block, even when they are not in the same block.

@echo Off
setlocal enabledelayedexpansion enableextensions


for /f "Tokens=1-7 Delims=_" %%P in ("Testing_This_GREAT_Thing_Of_An_IDEA") do (
  Echo %%P
  For %%a in (P Q R S T U V ) do (
    Call :read_meta_var term %%a
    If not "!term!"=="" Call set word.%%a=%%term%%
    Echo word.%%a = "!word.%%a!"
  )
)
pause
exit /b

:read_meta_var
REM *** %1=Variable to store the result
REM *** %2=Character of the meta variable to read

for %%d in ("dummy") do (
  set "%1=%%%2"
)
jeb
  • 78,592
  • 17
  • 171
  • 225
  • this is almost _exactly_ what I had decided to settle on as I fleshed out the Subroutine I posted. Thank you for confirming my suspicions! – k1dfr0std Dec 11 '22 at 09:37
2

Adding another answer I stumbled upon which operates on the premise presented by @T3RR0R's Comment to my original post - @T3RR0R Linked to this article at dostips.com, where we are presented with the idea of parsing substrings from one string using whatever delimiter we want.

Modifying one of the examples set within this article, we can arrive at the following which uses a zero-indexed "array" like we're used to seeing in almost all other programming languages.

set "x=Testing_This_GREAT_Thing_Of_An_IDEA"
set i=0
set "x.!i!=%x:_=" & set /a i+=1 & set "x.!i!=%"
REM output x var's:
set x.

Which yields the fantastically succinct output of:

x.0=Testing
x.1=This
x.2=GREAT
x.3=Thing
x.4=Of
x.5=An
x.6=IDEA

I played around with trying to set "x.a"-"x.g" using variable positioning and the delayed expansion of i where it is asserted that "verb=abcdefghijklmnopqrstuvwxyz", by using:

set "x.!y!=%x:_=" & set /a i+=1 & Call set "y=%%verb:~!i!,1%%" & set "x.!y!=%"

Unfortunately, it always ended with x.a=Testing and nothing else defined, while y=IDEAverb:~7,1 always occurred, boggling my mind. . . I would love to get this to work in a one-liner!

Fortunately, if I take a For /l numerical loop, I can accomplish my goal in 2 lines with the assertion that x and verb are already set previously as described using the original substitution line:

set "x.!i!=%x:_=" & set /a i+=1 & set "x.!i!=%"
For /l %%l in (0,1,!i!) do (For /f "Tokens=1" %%q in ("!verb:~%%l,1!") do ( set "word.%%q=!x.%%l!" ) )

If it is possible to perform this variable substitution/positioning in one line using the calculation to i in one line, this would be fantastic, otherwise, for the sake of sanity, an extra line is not a problem for me.

k1dfr0std
  • 379
  • 1
  • 15
  • 1
    See [my answer](https://stackoverflow.com/a/74774377/778560) with the desired one-liner solution... – Aacini Dec 12 '22 at 16:43
2

I think you should read the whole article at dostips.com because in the last page this method is explained:

@echo off
setlocal EnableDelayedExpansion

set "str=Testing_This_GREAT_Thing_Of_An_IDEA"
set "vars=P Q R S T U V"

set "p=%%" & set "v=%vars: =" & set "s=!str:*_=!" & call set "word.!v!=!p!str:_!s!=!p!" & set "str=!s!" & set "v=%" & set "word.!v!=!s!"

set word

Output:

word.P=Testing
word.Q=This
word.R=GREAT
word.S=Thing
word.T=Of
word.U=An
word.V=IDEA

EDIT: New method added

After carefully read your answer, I think this is what you are looking for:

@echo off
setlocal EnableDelayedExpansion

set "x=Testing_This_GREAT_Thing_Of_An_IDEA"
set "verb=abcdefghijklmnopqrstuvwxyz"

set "p=%%" & set i=0 & set "x.%verb:~0,1%=%x:_=" & set /a i+=1 & call set "x.!p!verb:~!i!,1!p!=%"

set x

Finally, a more "traditional" method, using just FOR's:

@echo off
setlocal EnableDelayedExpansion

set "x=Testing_This_GREAT_Thing_Of_An_IDEA"
set "y=P Q R S T U V"

for %%n in (^"^
%Don't remove this line%
^") do for %%a in ("!x:_=%%n!") do (
   for /F "tokens=1*" %%b in ("!y!") do set "word.%%b=%%~a" & set "y=%%c"
)

set word
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • Is there an emoji for "MindBlown" ??? I must break this down so I understand. . . `set p=%%` is used in the `call set` line to instantiate the fact that I want to convert `%%verb:~!i!,1%%` appropriately at the end - that's insane. Now, I _did_ read the whole article, but so many of those items were WAY above my head at the time of day I was reading. Looking at the original option, it was to satisfy the original posting using "P Q R S" and splitting _*BOTH*_ strings by their respective delimiters `"_"` and `" "` respectively . . . Do I have this correct? – k1dfr0std Dec 13 '22 at 00:43
  • And this For Loop - HOW ON EARTH do you figure this out?!? So - `for %%n . . .` sets up what exactly - is it using the `crlf` to do something? If you could break this last part down a little more - this would be wonderful - truly a magical solution. Thank you! – k1dfr0std Dec 13 '22 at 00:47
  • The method to split two variables _in the same line_ is described with detail at [this post](https://www.dostips.com/forum/viewtopic.php?f=3&t=6429&start=30#p55819). The `for %%n . . .` trick replaces the underscore by a `CrLf` so it splits _one string_ in _several lines_. In this way, you don't need to worry about how many items a string have (that must be processed with variable number of `tokens=1-7` and different `%%P %%Q ...` parameters). Instead, process _each part_ with a standard (no `/F` option) `FOR` command. – Aacini Dec 13 '22 at 19:45
  • Do you know that you can change the selected Best Answer if you wish? **`;)`** – Aacini Dec 13 '22 at 19:48
  • I can - however - for the project I'm working on, I settled on the answer provided by Jeb initially - I still need to work out the logic in my mind how I'd make this answer tie into what was built - as it stands, sending everything to a subroutine allows me some flexibility on what I'm doing with every token at run-time which (at least on first glance) will be more difficult in my mind until I can wrap my head around this better. I'm thinking long term I might switch to this, and produce these substrings and then do what I need after separate from the loop. A project for another day though. – k1dfr0std Dec 14 '22 at 20:10