Re: stringlength.cmd - just created - for anybody who can use it

An pretty old topic ,but I also needed this.I've used almost the same thing , but in this above I see two potential problems - If the string contains double quotes the if checks may fail , and there's no initial check if the string is empty.Here I'm trying to deal with this (but not completely works with the second parameter may I should remove it as an option):

:strlen [%1 -string, %2 variable to store result in]
setlocal
set string=%~1
rem if the string contains double quotes it will harm the IF checks
set string=%string:"=.%
set var=%~2
set /a counter=0
if "%string%" equ "" goto :return
:loop
rem counter will hold the 1/2 of the string lenght
set /a counter=%counter%+1
set string=%string:~1,-1%
if "%string%" equ "" (
goto :endloop
)
goto :loop
:endloop
set string=%~1
set string=%string:"=.%
set /a counter=2*%counter%-1
rem checking if the string is with even or with uneven lenght
call set string=%%string:~%counter%%%
if "%string%" neq "" set /a counter=%counter%+1
echo %counter%
:return
endlocal & set %var%=%counter% >nul 2>&1

I'm also trying to "eat" the string from two directions with a tiny hope that this will be faster for a long strings.

Re: stringlength.cmd - just created - for anybody who can use it

Here is a survey of algorithms for computing string length. One general technique in common is to use delayed expansion so that the routines compute the correct length no matter what characters are contained within the string.

Each of the routines below has identical functionality and nearly identical limits. The only slight differences are the maximum length that can be computed. All methods approach the 8191 maximum byte length, but the actual limit varies slightly.

Each routine requires the name of a variable as the first parameter. Each routine measures the length of the string value stored within the named variable, and properly computes 0 if the variable is not defined.

Each routine optionally takes the name of a return variable as the 2nd parameter, where the result is stored. If the return variable is not specified, then the result is ECHOed to stdout.

I placed each routine in its own file to get accurate timings. For each routine, I report the amount of seconds it takes to compute the length of various string lengths 1000 times.

:strLen1The simplest (and generally slowest) is a brute force linear technique that is basically the same as the original post in this thread. It is fine for short strings, but is awful for even moderately long strings. The problem is that GOTO is quite slow. The routine is even worse if the routine is embedded in a long batch file, because batch must scan the entire file to loop back - the longer the file, the worse the performance.

:strLen2This simple optimization uses a FOR /L loop instead of GOTO to perform the brute force linear length search. It makes short strings a bit slower, but is a major improvement for moderately long strings. It is still quite slow for very long strings.

:strLen3Here is the first algorithm that has decent performance that does not degrade with long strings. It uses the rarely used FINDSTR /O option. The limiting performance factor is the startup time for the external FINDSTR command and the extra time it takes to launch 2 CMD threads.

:strLen5This is a minor optimization of :strLen4 that on my machine gives the best performance. The only difference is it assumes the name of the temporary file is already initialized, and it does not bother deleting the temporary file when finished. The same temp file gets reused for each call.

:strLen6This is a very fast algorithm developed at DosTips. It uses a binary search to detect the length of the string. It only requires 13 iterations for any length string supported by batch. On some machines, this routine is slightly faster than :strlen4, but on my machine it is a bit slower. The biggest advantage over :strLen4 and :strLen5 is this routine does not need a temp file.

Have no idea how fast this is :-)(may be it's worth to try also with 4 - it will require one more nested IF and one more nested FOR and the IF checks will be almost the same number as the loops in the outer FOR.Also could try to put two item in inner FOR instead of nested IF but this will require one GOTO ....)

Re: stringlength.cmd - just created - for anybody who can use it

It's more meaningful to perform a large number iterations and time that. I found minor fluctuations in system load meant that some runs took 0.01s while others reported 0.05s with the exact same parameters.

Here's my own tunable (if not very successful at larger sizes) attempt and the harness I used to test it (calls a timing script I wrote a couple of years ago, included at the end):

Re: stringlength.cmd - just created - for anybody who can use it

Thank you Simon,

Your solution does resolve the issue, albeit a deviation.

With respect to the strlen functions, I believe that the functions would be most useful when used in context where a variable is extrapolated in line from another source, for example in my demonstration.

From my naive perspective, it would seem that hard-coding the string and testing the function provides the expected results, where as if I "stringify" (for want of a better word) a variable and use it in context we get a different result, as I believe I have demonstrated.

This to me suggests there is something subtly different in the formatting of the hard-coded string and my "stringification" of the variable.

I would be grateful if someone could point out that subtlety, or point me to some documentation that would explain the difference.

Don't get me wrong because I am impressed with the strlen solutions, and I still believe the strlen functions are the best common solutions to add to a library. I just need to understand how to use the function it in context, and correctly.

Re: stringlength.cmd - just created - for anybody who can use it

This example is intended to be simple and easy to follow rather than particularly high performance with long strings. It is probably most similar to StrLen2 that Dave Benham posted above.Theres also a link back to this thread.

Re: stringlength.cmd - just created - for anybody who can use it

nice idea to add the strlen function to the site. I can understand that you take a simple implementation, but ....Your version fails in too many situaltions. All special characters breaks your code.

strlen.cmd "Cat&Dog"strlen.cmd 1^>2

And I can't see why you should use any replace operations.

I would change the code to

Echo off
Setlocal EnableDelayedExpansion
Set "_str=%*"
:: Test if empty
if not defined _str Echo String Length = 0 & ENDLOCAL & set _strlen=0&goto:eof
For /l %%g in (0,1,8191) do (
REM extract one character
Set "_char=!_str:~%%g,1!"
REM if _char is empty we are at the end of the string
if not defined _char Echo String Length = %%g & ENDLOCAL & set _strlen=%%g& goto:eof
)

Re: stringlength.cmd - just created - for anybody who can use it

^ Thanks Jeb that example is better, interestingly your version is similar to the strlen function in the Batchography book which I have just been reading.I left in the removal of quotes just so that the script/function can be called passing a string with or without surrounding quotes. Also I mentioned the special characters and linked back to this thread.

Edit: after playing around with this some more, I switched the web page to use strLen7 as it is quite a bit faster.

Re: stringlength.cmd - just created - for anybody who can use it

I know this topic is old and maybe an addition has not much worth by now, but I stumbled on it so I'll just add my solution.It requires no temp files and runs in constant time.

It employs "findstr /O", which will output 'charoffset: line' for each matching line. The routine pipes two text lines to findstr, the first containing the input string, the second just empty to read it's character offset.That offset would be greater by 3 respect to the first line's length, not sure why but it may have to do with the <LF><CR> pair.The requested length is set as the second line offset - 5, that keeps into account the "" used to make a more robust expansion.

:: WARNING: The input string can contain any special character but '%', even if escaped as '%%'
:: it will just be missing from input vars %1, %2 etc.
:: Usage:
:: call :StrLen OUT_VAR "string"
:: call :StrLen OUT_VAR "%STR_VAR%"
:StrLen
setlocal
if "%~1"=="" endlocal & echo ERROR: StrLen: not enough params & goto :EOF
:: I don't know why, but each '^' character is doubled when it's passed in a string parameter, i.e. call :StrLen LEN "ab^c" will set "%~2"=="ab^^c"
set "TMP_STRING=%~2"
if defined TMP_STRING set "TMP_STRING=%TMP_STRING:^^=X%"
for /f "delims=:" %%a in ('^(echo."%TMP_STRING%"^&echo.^)^|findstr /O /R "$"') do set /A "TMP_LEN=%%a-5"
endlocal & set "%~1=%TMP_LEN%"
goto :EOF

One change I have made is to make the script accept the string directly (by value) rather than a variable name.

This means that any string containing spaces must be surrounded with quotes, but thats a pretty standard way of doing things.It also means that the surrounding quotes are correctly stripped before the length is calculated.

Many of the scripts above include the line:

set "s=!%~1!"

which will leave the quotes in place, the %~1 is in effect trying to remove quotes from the variable name not the contents of the variable.