How do you get the string length in a batch file?
As there is no built in function for string length, you can write your own function like this one:
@echo offsetlocalREM *** Some tests, to check the functionality ***REM *** An emptyStr has the length 0set "emptyString="call :strlen result emptyStringecho %result%REM *** This string has the length 14set "myString=abcdef!%%^^()^!"call :strlen result myStringecho %result%REM *** This string has the maximum length of 8191setlocal EnableDelayedExpansionset "long=."FOR /L %%n in (1 1 13) DO set "long=!long:~-4000!!long:~-4000!"(set^ longString=!long!!long:~-191!)call :strlen result longStringecho %result%goto :eofREM ********* function *****************************:strlen <resultVar> <stringVar>( setlocal EnableDelayedExpansion (set^ tmp=!%~2!) if defined tmp ( set "len=1" for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do ( if "!tmp:~%%P,1!" NEQ "" ( set /a "len+=%%P" set "tmp=!tmp:~%%P!" ) ) ) ELSE ( set len=0 ))( endlocal set "%~1=%len%" exit /b)
This function needs always 13 loops, instead of a simple strlen function which needs strlen-loops.
It handles all characters.
The strange expression (set^ tmp=!%~2!)
is necessary to handle ultra long strings, else it's not possible to copy them.
You can do it in two lines, fully in a batch file, by writing the string to a file and then getting the length of the file. You just have to subtract two bytes to account for the automatic CR+LF added to the end.
Let's say your string is in a variable called strvar
:
ECHO %strvar%> tempfile.txtFOR %%? IN (tempfile.txt) DO ( SET /A strlength=%%~z? - 2 )
The length of the string is now in a variable called strlength
.
In slightly more detail:
FOR %%? IN (filename) DO ( ...
: gets info about a fileSET /A [variable]=[expression]
: evaluate the expression numerically%%~z?
: Special expression to get the length of the file
To mash the whole command in one line:
ECHO %strvar%>x&FOR %%? IN (x) DO SET /A strlength=%%~z? - 2&del x
I prefer jeb's accepted answer - it is the fastest known solution and the one I use in my own scripts. (Actually there are a few additional optimizations bandied about on DosTips, but I don't think they are worth it)
But it is fun to come up with new efficient algorithms. Here is a new algorithm that uses the FINDSTR /O option:
@echo offsetlocalset "test=Hello world!":: Echo the length of TESTcall :strLen test:: Store the length of TEST in LENcall :strLen test lenecho len=%len%exit /b:strLen strVar [rtnVar]setlocal disableDelayedExpansionset len=0if defined %~1 for /f "delims=:" %%N in ( '"(cmd /v:on /c echo(!%~1!&echo()|findstr /o ^^"') do set /a "len=%%N-3"endlocal & if "%~2" neq "" (set %~2=%len%) else echo %len%exit /b
The code subtracts 3 because the parser juggles the command and adds a space before CMD /V /C executes it. It can be prevented by using (echo(!%~1!^^^)
.
For those that want the absolute fastest performance possible, jeb's answer can be adopted for use as a batch "macro" with arguments. This is an advanced batch technique devloped over at DosTips that eliminates the inherently slow process of CALLing a :subroutine. You can get more background on the concepts behind batch macros here, but that link uses a more primitive, less desirable syntax.
Below is an optimized @strLen macro, with examples showing differences between the macro and :subroutine usage, as well as differences in performance.
@echo offsetlocal disableDelayedExpansion:: -------- Begin macro definitions ----------set ^"LF=^%= This creates a variable containing a single linefeed (0x0A) character =%^":: Define %\n% to effectively issue a newline with line continuationset ^"\n=^^^%LF%%LF%^%LF%%LF%^^":: @strLen StrVar [RtnVar]:::: Computes the length of string in variable StrVar:: and stores the result in variable RtnVar.:: If RtnVar is is not specified, then prints the length to stdout.::set @strLen=for %%. in (1 2) do if %%.==2 (%\n% for /f "tokens=1,2 delims=, " %%1 in ("!argv!") do ( endlocal%\n% set "s=A!%%~1!"%\n% set "len=0"%\n% for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (%\n% if "!s:~%%P,1!" neq "" (%\n% set /a "len+=%%P"%\n% set "s=!s:~%%P!"%\n% )%\n% )%\n% for %%V in (!len!) do endlocal^&if "%%~2" neq "" (set "%%~2=%%V") else echo %%V%\n% )%\n%) else setlocal enableDelayedExpansion^&setlocal^&set argv=,:: -------- End macro definitions ----------:: Print out definition of macroset @strLen:: Demonstrate usageset "testString=this has a length of 23"echo(echo Testing %%@strLen%% testString%@strLen% testStringecho(echo Testing call :strLen testStringcall :strLen testStringecho(echo Testing %%@strLen%% testString rtnset "rtn="%@strLen% testString rtnecho rtn=%rtn%echo(echo Testing call :strLen testString rtnset "rtn="call :strLen testString rtnecho rtn=%rtn%echo(echo Measuring %%@strLen%% time:set "t0=%time%"for /l %%N in (1 1 1000) do %@strlen% testString testLengthset "t1=%time%"call :printTimeecho(echo Measuring CALL :strLen time:set "t0=%time%"for /l %%N in (1 1 1000) do call :strLen testString testLengthset "t1=%time%"call :printTimeexit /b:strlen StrVar [RtnVar]:::: Computes the length of string in variable StrVar:: and stores the result in variable RtnVar.:: If RtnVar is is not specified, then prints the length to stdout.::( setlocal EnableDelayedExpansion set "s=A!%~1!" set "len=0" for %%P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do ( if "!s:~%%P,1!" neq "" ( set /a "len+=%%P" set "s=!s:~%%P!" ) ))( endlocal if "%~2" equ "" (echo %len%) else set "%~2=%len%" exit /b):printTimesetlocalfor /f "tokens=1-4 delims=:.," %%a in ("%t0: =0%") do set /a "t0=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100for /f "tokens=1-4 delims=:.," %%a in ("%t1: =0%") do set /a "t1=(((1%%a*60)+1%%b)*60+1%%c)*100+1%%d-36610100set /a tm=t1-t0if %tm% lss 0 set /a tm+=24*60*60*100echo %tm:~0,-2%.%tm:~-2% msecexit /b
-- Sample Output --
@strLen=for %. in (1 2) do if %.==2 ( for /f "tokens=1,2 delims=, " %1 in ("!argv!") do ( endlocal set "s=A!%~1!" set "len=0" for %P in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do ( if "!s:~%P,1!" neq "" ( set /a "len+=%P" set "s=!s:~%P!" ) ) for %V in (!len!) do endlocal&if "%~2" neq "" (set "%~2=%V") else echo %V )) else setlocal enableDelayedExpansion&setlocal&set argv=,Testing %@strLen% testString23Testing call :strLen testString23Testing %@strLen% testString rtnrtn=23Testing call :strLen testString rtnrtn=23Measuring %@strLen% time:1.93 msecMeasuring CALL :strLen time:7.08 msec