my own StrLen function

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
billrich
Posts: 70
Joined: 24 Apr 2012 05:36
Location: USA

Re: my own StrLen function

#16 Post by billrich » 23 Sep 2012 14:25

dbenham wrote:
The DosTips strlen function handles all possible strings up to the max length supported by batch (actually maxLength-1), and completes in the blink of an eye.

Dave Benham


I can find no examples of members using the DosTips strlen function other than the example where the user furnishes the strings one at time.

The following code gets the strings from dir /b a*.bat. May we see the correct way to gather the strings for the Dostips strlen function?

Thanks for your help.

Code: Select all


@echo off
setlocal enabledelayedexpansion
for /f "delims=" %%i in ('dir /b a*.bat') do (
set "string="
set string=%%i
echo string=!string!
   CALL :StrLen string Len
   ECHO  Length = !Len!
)
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


Output:

C:\test>tipsstr.bat
string=A.bat
Length = 5
string=AA.bat
Length = 6
string=aaron.bat
Length = 9
string=ab.bat
Length = 6
string=abc.bat
Length = 7
string=abcd.bat
Length = 8
string=Abhi.bat
Length = 8
string=abhi2.bat
Length = 9
string=Abnew.bat
Length = 9
string=acall.bat
Length = 9
string=add.bat
Length = 7
string=add2.bat
Length = 8
string=adh.bat
Length = 7
string=adhold.bat
Length = 10
string=agedel.bat
Length = 10
string=ana.bat
Length = 7
string=andrea.bat
Length = 10
string=anup.bat
Length = 8
string=arc.bat
Length = 7
string=arguments.bat
Length = 13

C:\test>

billrich
Posts: 70
Joined: 24 Apr 2012 05:36
Location: USA

Re: my own StrLen function

#17 Post by billrich » 27 Sep 2012 17:42

Code: Select all

@echo off
rem jimlen.bat  hello world
echo Usage: jimlen.bat hello world
setlocal enabledelayedexpansion
set string=%*
:loop
  set /A cnt+=1
  if not "!string:~%cnt%,1!"=="" goto loop
echo.string length = %cnt%
rem code posted by T.C. at computerhope.com

Output:
C:\test>jimlen.bat hello world
Usage: jimlen.bat hello world
string length = 11
C:\test>jimlen.bat 77777
Usage: jimlen.bat hello world
string length = 5
C:\test>jimlen.bat hello world
string length = 11
C:\test>jimlen.bat hello
string length = 5
C:\test>jimlen.bat 77777
string length = 5
C:\test>jimlen.bat <αßc??>,
string length = 8
C:\test>
p.s Some of the DosTips experts do not know how to run a program that requires arguments:
jimlen.bat hello world
Last edited by billrich on 02 Oct 2012 04:32, edited 3 times in total.

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: my own StrLen function

#18 Post by Squashman » 27 Sep 2012 18:12

billrich wrote:

Code: Select all

@echo off
setlocal enabledelayedexpansion
set string=%*
:loop
  set /A cnt+=1
  if not "!string:~%cnt%,1!"=="" goto loop

echo.string length = %cnt%

Try that with this string: !&%$^*()!

Squashman
Expert
Posts: 4486
Joined: 23 Dec 2011 13:59

Re: my own StrLen function

#19 Post by Squashman » 27 Sep 2012 18:59

Thought I would show this code for getting length. Was one posted buy a user on another forum a while back but of course it has issues with some of the poison characters. It is interesting what it does when you use all carets.

Mostly just posting this because of the concept it uses to get the length. Definitely not fool proof.

Code: Select all

@echo off
SetLocal
Set _Len=0
Set "_Str=%*"
If NOT Defined _Str Goto :EOF
Set _Str=%_Str:"=.%987654321
:_Loop
If NOT "%_Str:~18%"=="" Set _Str=%_Str:~9%& Set /A _Len+=9& Goto _Loop
Set _Num=%_Str:~9,1%
Set /A _Len=_Len+_Num
echo %_Len%
endlocal

Code: Select all

C:\Users\Squashman\Batch>outlen.bat !123456789123456789!
20

C:\Users\Squashman\Batch>outlen.bat %123456789123456789%
20

C:\Users\Squashman\Batch>outlen.bat %123456789123456789%&&
The syntax of the command is incorrect.

C:\Users\Squashman\Batch>outlen.bat %123456789123456789% 1
22

C:\Users\Squashman\Batch>outlen.bat %12345678^9123456789%
20

C:\Users\Squashman\Batch>outlen.bat %12345678^^9123456789%
20

C:\Users\Squashman\Batch>outlen.bat %12345678^^9123456789%^^
20

C:\Users\Squashman\Batch>outlen.bat ^^^^^^^^^^^^^^^
More?
More?
3

C:\Users\Squashman\Batch>

Liviu
Expert
Posts: 470
Joined: 13 Jan 2012 21:24

Re: my own StrLen function

#20 Post by Liviu » 27 Sep 2012 19:01

Squashman wrote:Try that with this string: !&%$^*()!
You are making it way too complicated ;-) Just run bill's code with no arguments at all, and prepare to be very very patient. Or, for a challenge, explain why the length of ^^ returns as 5. But I think we all know it's a waste of time.

Liviu
Expert
Posts: 470
Joined: 13 Jan 2012 21:24

Re: my own StrLen function

#21 Post by Liviu » 27 Sep 2012 19:10

Squashman wrote:Mostly just posting this because of the concept it uses to get the length.

Didn't follow it in full detail, but looks like it reduces the loops by a (linear) factor of 9. That's a clever trick, indeed, but dostips' :strlen easily beats it with the (exponential) log2 reduction.

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

Re: my own StrLen function

#22 Post by dbenham » 27 Sep 2012 20:11

I haven't done any rigorous timing, but I think this is about as fast as the DosTips StrLen function, though it uses a temporary file.

I think I first saw this basic technique in a StackOverflow post by Aacini. I don't know how long the idea has been around.

Code: Select all

@echo off

:strLen  strVar  [rtnVar]
setlocal enableDelayedExpansion
set "tempFile=%temp%\strLen%random%.txt"
>"%tempFile%" echo(!%~1!
for %%F in ("%tempFile%") do set /a "rtn=%%~zF - 2"
del "%tempFile%"
(endlocal
  if "%~2" neq "" (set "%~2=%rtn%") else echo %rtn%
)
exit /b


Dave Benham

Liviu
Expert
Posts: 470
Joined: 13 Jan 2012 21:24

Re: my own StrLen function

#23 Post by Liviu » 27 Sep 2012 21:46

dbenham wrote:I haven't done any rigorous timing, but I think this is about as fast as the DosTips StrLen function, though it uses a temporary file.

Maybe not literally "as fast" but close, yes. Not claiming full rigor, but running both on strings of increasing lengths, the dostips :strlen comes 10%-15% faster on my test machine. Pedantic footnote, it stops counting at length 8,185 while the code you quoted goes one byte farther i.e. gets 8,185 right but fails on 8,186.

Liviu

Post Reply