#1 19 Jun 2012 23:57

wquatan
Member
Registered: 19 Jun 2012
Posts: 16

String char-by-char

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

#2 20 Jun 2012 02:57

dbenham
Member
From: U.S. east coast
Registered: 15 Apr 2012
Posts: 111

Re: String char-by-char

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 big_smile


Dave Benham

Offline

#3 21 Jun 2012 15:26

wquatan
Member
Registered: 19 Jun 2012
Posts: 16

Re: String char-by-char

Hi Dave,

Thank you very very very much, was exactly what I needed, works great !

Kind regards

Offline

#4 28 Dec 2017 18:11

Sponge Belly
Member
From: Ireland
Registered: 01 Jan 2014
Posts: 9

Re: String char-by-char

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! smile

- SB

Offline

Board footer

Powered by FluxBB