Joe Cartano
Joe Cartano

Reputation: 3037

How to loop through tokens in a string?

Say I have a string such as foo:bar:baz, is it possible to loop through this string? It looked like you could tokenize lines of a file but the following will only echo 'foo' once.

for /f "tokens=1,2* delims=:" %%x in ("%%j") do echo %%x

Upvotes: 18

Views: 37196

Answers (4)

kikuchiyo
kikuchiyo

Reputation: 3421

This will parse the string into variables accessable outside of the loop (;

setlocal enabledelayedexpansion

set your_string="whatever:you:want"

for /f "tokens=1,2,3 delims=:" %%a in ('echo !your_string!') do (
    set first_sub_string=%%a
    set second_sub_string=%%b
    set third_sub_string=%%c
)

echo Congrats.  !your_string! was parsed as !first_sub_string!, !second_sub_string!, !third_sub_string!

Upvotes: 3

dbenham
dbenham

Reputation: 130889

Aacini beat me to my first solution. It can be improved by adding quotes so that the string can contain spaces and special characters and still give the correct result.

set "str=foo bar:biz bang:this & that"
for %%S in ("%str::=" "%") do echo %%~S

The solution has limitations:

  • No * or ? can appear in the string
  • Problems can arise if the string already contains quotes ("), especially if there are special characters as well

The second solution has bizarre syntax, but the concept is fairly straight forward. FOR /F with "string" will break on linefeed characters - each line will be processesed as its own string. The trick is to replace the : delimiter with a linefeed character. Note that the blank line in the solution below is a critical part of the tricky replacement. Also, the following line must start with the ! which terminates the delayed variable expansion. There should not be any leading spaces.

The other thing to worry about is the pesky FOR /F "EOL" option. We don't want to skip any values that start with the EOL character which is ; by default. Since we have eliminated the string delimiter :, we can safely use that as the EOL.

Finally, we need to use delayed expansion, but ! will be corrupted during %%S expansion if we don't first disable delayed expansion within the loop.

set "str=foo bar:biz bang:this & that "^& the other thing!":;How does this work?"
setlocal enableDelayedExpansion
set ^"str=!str::=^

!"
for /f "eol=: delims=" %%S in ("!str!") do (
  if "!!"=="" endlocal
  echo %%S
)

I believe this technique can handle just about anything you throw at it.

jeb was the first to show me how to work with line feeds within batch, and especially how to use this technique. It may even be posted already somewhere else on SO.

Upvotes: 11

PA.
PA.

Reputation: 29349

it does as expected, it tokenizes it to %%x %%y %%z. So instead of just processing %%x, you might...

for /f "tokens=* delims=:" %%x in ("foo:bar:baz") do (
  echo %%x
  echo %%y
  echo %%z
)

or if you don't know in advance how many items you got, you may...

@echo off
set string=foo:bar:baz
:again
for /f "tokens=1* delims=:" %%x in ("%string%") do (
   echo %%x 
   set string=%%y
)
if not .%string%==. goto again
echo done

Upvotes: 3

Aacini
Aacini

Reputation: 67216

set string=foo:bar:baz
for %%x in (%string::= %) do echo %%x

FOR value delimiters may be space, comma, semicolon and equal-sign. You may directly process a string if the elements are delimited with any of these characters. If not, just change the delimiter for one of these character (as I did above).

set string=foo bar,baz;one=two
for %%x in (%string%) do echo %%x

Upvotes: 21

Related Questions