Enumerating the delims of a FOR /F statement
-
27-04-2021 - |
Question
I have a FOR /F statement which I want it to enumerate the delims the command is parsing. For example:
FOR /F "delims=," %%A IN ("This,is,a,comma,delimited,sentence") DO (
some command to enumerate delims
)
:OUT
I want it to account for each delimited item in that sentence. In this case it would output 6
EDIT: I know the long way would be to do a check on each one.. but I'm trying to avoid that method:
IF %%A == [] SET enum=0 && GOTO:OUT
IF %%B == [] SET enum=1 && GOTO:OUT
etc.
Solution
There is NO way to directly enumerate items in a FOR /F "delims=..." command. The usual way to do that is via a loop that count one item, eliminate it from the sentence and repeat while there was a counted item.
However, depending on the specific delimiter and the rest of characters in the sentence, you may use a FOR command (with no /F option) that will REPEAT its code with each item separated BY THE STANDARD BATCH DELIMITERS, that are comma, semicolon and equal-sign, besides spaces. In your particular example:
SET ENUM=0
FOR %%A IN (This,is,a,comma,delimited,sentence) DO SET /A ENUM+=1
directly count the number of comma-separated items. If the delimiter is a character other than comma, semicolon or equal-sign, a possible solution is a three steps method:
1- Replace spaces, comma, semicolon and equal-sign for another know character(s).
2- Replace the delimiter for any Batch standard delimiter (space, comma, etc).
3- Use a simple FOR to directly enumerate the items.
OTHER TIPS
There IS a way to directly enumerate items in a FOR /F "delims=..." command.
You only need to insert some newlines into the string.
setlocal EnableDelayedExpansion
set LF=^
rem ** Two empty lines are required
set count=0
FOR /F "tokens=* delims=" %%a in ("item1!LF!item2!LF!item3") DO (
set /a count+=1
echo !count!: "%%a"
)
echo(
set "CSV=This,is,a,comma,delimited,sentence"
echo Or with comma separeted text: !CSV!
for %%L in ("!LF!") do set "CSV=!CSV:,=%%~L!"
set count=0
FOR /F "tokens=* delims=" %%a in ("!CSV!") DO (
set /a count+=1
echo !count!: "%%a"
)
Aacini's suggestion to use a simple FOR instead of FOR /F is a good solution, unless the string might contain wildcard characters *
or ?
. The ?
character could be protected by search and replace, but there is no efficient way to replace *
in batch.
If you run into the wildcard problem then you can revert to using FOR /F in a loop to parse one word at a time. Most people use GOTO to accomplish the loop because you have no way of knowing how many words you will find. But GOTO is relatively slow. You can achieve a significant performance boost by using an outer FOR loop (not FOR /L) with an arbitrarily large number of items. Within the body you can exit the loop with a GOTO whenever there are no more words. If the loop falls through without exhausting the words, you can use a GOTO to restart the loop. An outer loop with 100 items will only perform 1 GOTO per 100 parsed words.
@echo off
setlocal enableDelayedExpansion
set "str=This,is,a,comma,delimited,sentence"
set "L10=1 2 3 4 5 6 7 8 9 0"
:loop - The outer FOR loop can handle 100 words before a single GOTO is needed
for %%. in (%L10% %L10% %L10% %L10% %L10% %L10% %L10% %L10% %L10% %L10%) do (
for /f "tokens=1* delims=," %%A in ("!str!") do (
echo %%A
if "%%B" == "" goto :break
set "str=%%B"
)
)
goto :loop
:break
As with all FOR loops, you must worry about corruption of !
and ^
if delayed expansion is enabled when the %%A variable is expanded.
FOR /L should not be used for the outer loop because FOR /L always finishes counting all iterations, even if you use GOTO within the body.