You are not logged in.
Pages: 1
I've been searching the net for days now, maybe the wrong places, to find an example how to proceed in processing a string, char-by-char in a bat/cmd.
What I'm looking after is something like :
for every char in string (a variable, a parameter, or a 'string')
(
do something with char
do something else with char
)
Someone knows or has an example how todo that ?
Thanks
Offline
Here is an old school method using a GOTO loop. It works fine, but it is relatively slow, especially for large string lengths.
@echo off
setlocal enableDelayedExpansion
set string=ABCDEFG
set pos=0
if not defined string goto :done
:parseChars
set "chr=!string:~%pos%,1!"
if not defined chr goto :done
echo The char at position %pos% = !chr!
echo the char !chr! hasn't changed of course
set /a pos+=1
goto :parseChars
:done
echo done
GOTO and CALL are both relatively slow operations. It is best to reduce the number of CALL and GOTO executions to a minimum.
Here is a FOR /L loop solution that iterates the maximum length of a variable without using GOTO. It sort of breaks out of the loop when it finds the end of the string by using GOTO. But the FOR /L silently continues iterating behind the scenes until it reaches the end condition. (FOR /L is the only FOR variant that does not fully break out immediately upon executing GOTO). This solution performs about the same for small strings, but is much faster for large strings.
@echo off
setlocal enableDelayedExpansion
set string=ABCDEFG
if defined string for /l %%N in (0 1 8191) do (
set "chr=!string:~%%N,1!"
if not defined chr goto :done
echo The char at position %%N = !chr!
echo the char !chr! hasn't changed of course
)
:done
echo done
For the ultimate in performance, you can use the DOSTIPS StrLen function (http://www.dostips.com/DtCodeCmdLib.php#Function.strLen) to quickly get the actual string length and use that value to set the end condition in the FOR /L loop. It uses significantly more code, but it is actually the fastest in nearly all cases.
@echo off
setlocal enableDelayedExpansion
set string=ABCDEFG
call :strLen string len
set /a len-=1
for /l %%N in (0 1 %len%) do (
set "chr=!string:~%%N,1!"
echo The char at position %%N = !chr!
echo the char !chr! hasn't changed of course
)
echo done
exit /b
:strLen string len -- returns the length of a string
:: -- string [in] - variable name containing the string being measured for length
:: -- len [out] - variable to be used to return the string length
:: Many thanks to 'sowgtsoi', but also 'jeb' and 'amel27' dostips forum users helped making this short and efficient
:$created 20081122 :$changed 20101116 :$categories StringOperation
:$source http://www.dostips.com
( SETLOCAL ENABLEDELAYEDEXPANSION
set "str=A!%~1!"&rem keep the A up front to ensure we get the length and not the upper bound
rem it also avoids trouble in case of empty string
set "len=0"
for /L %%A in (12,-1,0) do (
set /a "len|=1<<%%A"
for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"
)
)
( ENDLOCAL & REM RETURN VALUES
IF "%~2" NEQ "" SET /a %~2=%len%
)
EXIT /b
Actually there are macro versions of the StrLen function that are even faster because they eliminate the CALL of the subroutine. But I think that is a bit of overkill at this point.
Anyone interested in batch macros can search the DOSTIPS forum (http://www.dostips.com/forum/search.php) for the terms "macros" and "macro" in the title... and have loads of fun
Dave Benham
Offline
Hi Dave,
Thank you very very very much, was exactly what I needed, works great !
Kind regards
Offline
Hi Everyone,
Apologies for reviving a 5-year-old thread, but I came up with the following:
@echo off & setLocal enableExtensions disableDelayedExpansion
(call;) %= sets errorLevel to 0 =%
set "testStr=uncopyrightable"
call :splitStr testStr
if errorLevel 1 (
>&2 echo(string is %errorLevel% char(s^) in length
) else (
>&2 echo(empty string
goto die
) %= if =%
goto end
:die
(call) %= sets errorLevel to 1 =%
:end
endLocal & goto :EOF
:splitStr string=
:: outputs string one character per line
setLocal disableDelayedExpansion
set "var=%1"
set "chrCount=0" & if defined var for /f "delims=" %%A in ('
cmd /v:on /q /c for /l %%I in (0 1 8190^) do ^
if "!%var%:~%%I,1!" neq "" (^
echo(:^!%var%:~%%I^,1^!^) else exit 0
') do (
set /a chrCount+=1
echo%%A
) %= for /f =%
endLocal & exit /b %chrCount%
The subroutine is expansion-insensitive, has no goto loop, and prints all characters including CR and LF.
Enjoy and HNY!
- SB
Offline
Pages: 1