Brenton
Brenton

Reputation: 35

In batch split a string to new lines in file by delimiter

In batch I'm trying to split a string into substrings preferably based on a delimiter.

This example works but is there a better way to do this:

for /f "tokens=1-20 delims=:" %%a in (string.txt) do (
echo %%a& echo.%%b& echo.%%c& echo.%%d& echo.%%e& echo.%%f& echo.%%g& echo.%%h& echo.%%i& echo.%%j
echo.%%k& echo.%%l& echo.%%m& echo.%%n& echo.%%o& echo.%%p& echo.%%q& echo.%%r& echo.%%s& echo.%%t
) >substrings.txt

I have tried this code from Magoo which works for default delimiters but fails using colon:

@echo off
setLocal 
for /f "delims=:" %%a in (string.txt) do (
for %%i in (%%a) do echo %%i >>substrings.txt
)

I have also tried this code from Aacini but it seems to fail using special characters.

@echo off
setlocal EnableDelayedExpansion

set i=1
set "x=%string%"
set "x!i!=%x::=" & set /A i+=1 & set "x!i!=%"
set x >substrings.txt

An example %string% var or string.txt is:

Select project:/option:report name="Sustainability":option value="201":Huonville:/option:/report:report name="Energy and Water Management":option value="102":Cygnet:/option:/report:report name="Tree Management":option value="101":Cygnet:/option:/report:option disabled="disabled":/option:/select

I am trying to output %string% var or string.txt to substring.txt as follows:

Select project
/option
report name="Sustainability"
option value="201"
Huonville
/option
/report
report name="Energy and Water Management"
option value="102"
Cygnet
/option
/report
report name="Tree Management"
option value="101"
Cygnet
/option
/report
option disabled="disabled"
/option
/select

Any help would be greatly appreciated. Thanks

Upvotes: 1

Views: 1001

Answers (3)

ScriptKidd
ScriptKidd

Reputation: 841

See @dbenham's AMAZING CERTUTIL string replacement technique. It works for any characters, even exclams!

@echo off
====SETLOCAL EnableDelayedExpansion EnableExtensions


set "B=^!"
set "C=^"
set ^"L=^
%===Line Feed===%
"
for /F "eol=N" %%C in ('wmic os get Name /value') do set "R=%%C" Carriage Return
set ^"E=!R!!L!" CRLF


>nul 2>&1 certutil -f -encodehex String.txt "%temp%\hex.txt" 4


pushd "%temp%"
>expand.txt (FOR /F "delims=" %%A in (hex.txt) do FOR %%B in (%%A) do (
    set "char=%%B"
    REM ! --> !B! ###
    set "char=!char:21=21 42 21!"
    REM ^ --> !C! ###
    set "char=!char:5e=21 43 21!"
    REM <CR> --> !R! ###
    set "char=!char:0a=21 4c 21!"
    REM <LF> --> !L! ###
    set "char=!char:0d=21 52 21!"


    REM : --> !R!!L! ###
    set "char=!char:3a=21 45 21!"
    echo(!char!
))


>nul 2>&1 certutil -f -decodehex expand.txt rawContent.txt
for /f delims^=^ eol^= %%A in (rawContent.txt) do set "modified=%%A"
del hex.txt expand.txt rawContent.txt
popd


>substring.txt (
echo(!modified!
)

Upvotes: 1

Brenton
Brenton

Reputation: 35

This is a summary of what Stephan came up with.

@echo off
setlocal enabledelayedexpansion
set /p string=<"input.txt"
set "string=%string: =@%"
set "string="%string::=" "%"
(for %%a in (%string%) do (
  set "output=%%~a"  
  echo !output:@= !
))>output.txt

Set string or input text file (modify line 3).

set /p string=<"input.txt"

The delimiter in this example is colon [:] which follows after [string:] (modify line 5).

set "string="%string::=" "%"

If string or input.txt contains quotes %string% may need to be double quoted (modify line 3).

for /f "delims=" %%a in (input.txt) do (set string="%%a")

@echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in (input.txt) do (set string="%%a")
set "string=%string: =@%"
set "string="%string::=" "%"
(for %%a in (%string%) do (
  set "output=%%~a"  
  echo !output:@= !
))>output.txt

Upvotes: 0

Stephan
Stephan

Reputation: 56180

When you use for /f, you need to know how many tokens there are (and there is a limit for max tokens).

You need a plain for loop, but you can't choose, which delimiter should be used.

So replace every delimiter with a space. Be sure to have quotes around each "token" to take care of original spaces. To do this, put quotes around the whole string and replace the delimter : with " ":

@echo off
setlocal enabledelayedexpansion
set "string=Select project:/option:report name="Sustainability":option value="201":Huonville:/option:/report:report name="Energy and Water Management":option value="102":Cygnet:/option:/report:report name="Tree Management":option value="101":Cygnet:/option:/report:option disabled="disabled":/option:/select""

set "string=%string: =@%"
set "string="%string::=" "%"
(for %%a in (%string%) do (
  set "out=%%~a"  
  echo !out:@= !
))>out.txt
echo take a look at the modified string:
echo %string%
echo/
type out.txt

Another approach (just for academic reasons):

 @echo off
setlocal 
set "string=Select project:/option:report name="Sustainability":option value="201":Huonville:/option:/report:report name="Energy and Water Management":option value="102":Cygnet:/option:/report:report name="Tree Management":option value="101":Cygnet:/option:/report:option disabled="disabled":/option:/select"

call :recur %string%
goto :eof

:recur
rem echo loop with %*
for /f "tokens=1,* delims=:" %%a in ("%*") do ( 
  echo %%a
  if not "%%~b" == "" call :recur %%b
  goto :eof
)
echo.

Note: there is a recursion limit (due to stack-size). It works with the given string, but may fail when the string contains more "tokens".

Upvotes: 4

Related Questions