Search code examples
for-loopbatch-filecmdtokenbatch-processing

Batch probblem: Cant iterate through string variable


I'm going crazy for 2 days with this simple task: iterate through a 5 line string with delimiters (or a file with the same content). After I find a delimiter symbol I expect to write that line to the file, then add echo for a cr/lf representation and do next iteration for a next piece of string.

For academic purposes I recreate the code like that:

@echo off
setlocal EnableDelayedExpansion 
set "LF=&echo."
set "dlm=+"
set "s1=A A A" 
set "s2=B B B" 
set "s3=C C C" 
set "s4=D D D" 
set "s5=E E E" 

set "s=%s1%%dlm%%s2%%dlm%%s3%%dlm%%s4%%dlm%%s5%%dlm%"

for /f "tokens=* delims=+" %%i in ("%s%") do (
    echo %%i>>test.txt
    echo. >>test.txt
)
pause

The output is like:

A A A+B B B+C C C+D D D+E E E+
newline

When I want this

A A A
B B B
C C C
D D D
E E E

When I change token to 1 or 2 it returns the correct line

How to get those sub strings and write them to the file? Why tokens don't work?

I tried to put this into another loop and pass token number as !j!, but it doesn't work. I also thought of a few goto but think it's a bad practice.


Solution

  • The subroutine split_supplied_line in the following batch code snippet should do the trick for (almost) any number of substrings and (almost) any delimiter. No matter whether there is a trailing delimiter.

    @ECHO OFF
    SETLOCAL EnableExtensions DisableDelayedExpansion
    set "LF=&echo."
    set "dlm=+"
    set "s1=A A A" 
    set "s2=B B B" 
    set "s3=C C C" 
    set "s4=D D D" 
    set "s5=E E E" 
    set "s=%s1%%dlm%%s2%%dlm%%s3%%dlm%%s4%%dlm%%s5%%dlm%"
    rem set "s=%s1%%dlm%%s2%%dlm%%s3%%dlm%%s4%%dlm%%s5%" without trailing %dlm%
    
    call :split_supplied_line "%s%" "%dlm%" "72351984test.txt"
    goto :eof
    
    :split_supplied_line
    set "restofline=%~1" 1st parameter: line to split
    set "delims=%~2"     2nd parameter: delimiter character
    set "tofile=%~3"     3rd parameter: file where to write
    :in_split_supplied_line
    call set "noplusline=%restofline:%delims%=%"
    if "%noplusline%"=="%restofline%" (
      SETLOCAL EnableDelayedExpansion
      echo !restofline!>>"%tofile%"
      ENDLOCAL
      goto :eof
    )
    for /f "tokens=1,* delims=%delims%" %%i in ("%restofline%") do (
        echo %%i>>"%tofile%""
        set "restofline=%%j"
    )
    if ""=="%restofline%" goto :eof
    goto :in_split_supplied_line
    

    Output: 2>nul del 72351984test.txt & .\SO\72351984.bat & type 72351984test.txt

    A A A
    B B B
    C C C
    D D D
    E E E
    

    However, there is a more tricky approach (unfortunately, a trailing delimiter adds a blank line into the output):

    @ECHO OFF
    SETLOCAL EnableExtensions DisableDelayedExpansion
    set "LF=&echo."
    set "dlm=+"
    set "s1=A A A" 
    set "s2=B B B" 
    set "s3=C C C" 
    set "s4=D D D" 
    set "s5=E E E" 
    set "s=%s1%%dlm%%s2%%dlm%%s3%%dlm%%s4%%dlm%%s5%%dlm%"
    rem set "s=%s1%%dlm%%s2%%dlm%%s3%%dlm%%s4%%dlm%%s5%" without trailing %dlm%
    
    >72351984test.txt (echo %s:+=&echo.%)
    
    ENDLOCAL
    goto :eof
    

    Output: 2>nul del 72351984test.txt & .\SO\72351984a.bat & type 72351984test.txt

    A A A
    B B B
    C C C
    D D D
    E E E