2

I want to parse through a single line of text where the words are separated by a space and store each word in its own array simulating variable. According to ss64 I should be able to do this. I may not be understanding delims or tokens because my code works for 1 iteration and stops.

::@echo off
setlocal enabledelayedexpansion
set string=foo bar baz
set /a index=0

for /F "tokens=* delims= " %%i in ("foo bar baz") do (
    echo %%i
    echo !index!
    set words[%index%]=%%i
    set /a index+=1
    echo !index!
)

set words[

Here is the output I get with debug echoes:

C:\Users\isimm\Desktop\batintercept>stringparse.cmd

C:\Users\isimm\Desktop\batintercept>setlocal enabledelayedexpansion

C:\Users\isimm\Desktop\batintercept>set string=foo bar baz

C:\Users\isimm\Desktop\batintercept>set /a index=0

C:\Users\isimm\Desktop\batintercept>for /F "tokens=* delims= " %i in ("foo bar baz") do (
echo %i
 echo !index!
 set words[0]=%i
 set /a index+=1
 echo !index!
)

C:\Users\isimm\Desktop\batintercept>(
echo foo bar baz
 echo !index!
 set words[0]=foo bar baz
 set /a index+=1
 echo !index!
)
foo bar baz
0
1

C:\Users\isimm\Desktop\batintercept>set words[
words[0]=foo bar baz

tokens=* gives me the above output, tokens=1,2,3 gives me only the first word, tokens=1 or tokens=2 or tokens=3 gives me the 1st, 2nd, or 3rd word. As I understand it "delims= " is redundant because by default spaces are used but it's the same whether I include delims or not.

I also tried using underscores in case there is some bug with spaces and also tried putting the text in a foo.txt file instead of a literal string. In both cases I get the same result as with the original string.

The output I'm expecting is:

words[0]=foo
words[1]=bar
words[2]=baz
isimmons
  • 2,016
  • 2
  • 20
  • 32
  • You seem to misinterpret how the `for /F` loop behaves: it does not iterate over the individual tokens defined by the `tokens=` and `delims=` options, it iterates over *lines* and returns all tokens extracted from a line in *one* iteration (occupying subsequent loop meta-variables as needed). Type `for /?` into a Command Prompt window to get a more detailed description… – aschipfl Sep 15 '21 at 17:26

2 Answers2

6

You may use this simpler method:

@echo off
setlocal EnableDelayedExpansion

set string=foo bar baz
set /a index=0

set "words[%index%]=%string: =" & set /A index+=1 & set "words[!index!]=%"

set words[

If you want to realize where the magic is, remove @echo off line, run the Batch file and carefully review the screen. Further details at Split string with string as delimiter

EDIT: New method added

You may also use this somewhat cryptic method:

@echo off
setlocal EnableDelayedExpansion

set string=foo bar baz
set /a index=0

for /F %%i in (^"!string: ^=^
% Do not remove this line %
!^") do (
   set words[!index!]=%%i
   set /A index+=1
)

set words[

In this method the spaces are replaced by a LF ASCII character... ;)

Aacini
  • 65,180
  • 12
  • 72
  • 108
  • I see where the magic is but don't understand the magic. I've been looking for something in Microsoft docs and on ss64 that mentions this and haven't found anything yet. I'm confused as to how this works without being in a loop. Seems like this is all about how delayed expansion works and what happens when you inject commands or expressions into the set command. 2 things I clearly don't understand and will need to keep looking into. But it works great so thanks. – isimmons Sep 15 '21 at 21:59
  • You may read a detailed discussion about this technique at [this thread](https://www.dostips.com/forum/viewtopic.php?f=3&t=6429). PS - Do you know that you may change your selected best answer if you wish? **`;)`** – Aacini Sep 17 '21 at 18:44
  • You may also read _the comment_ below [this answer](https://stackoverflow.com/a/33131797/778560) – Aacini Sep 17 '21 at 18:53
  • What happened? Is the method clearer now? – Aacini Sep 21 '21 at 23:39
3

I have tried this way and it worked for me:

@echo off & setlocal
setlocal enabledelayedexpansion
set string=foo bar baz
set /a index=0

rem temporaryVariable value always changes in the for loop.
set temporaryVariable=%string%

:loop
for /f "tokens=1*" %%a in ("%temporaryVariable%") do (
   set words[%index%]=%%a
   set /a index+=1
   set temporaryVariable=%%b
   )
if defined temporaryVariable goto :loop

set words[

I have based my answer on this one: https://stackoverflow.com/a/19009701/12367987