StrLen +Set Help

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

StrLen +Set Help

#1 Post by einstein1969 » 16 Oct 2013 12:47

hi,

I don't understand where i wrong

Code: Select all

@echo off & setlocal enabledelayedExpansion


set "st1="
For /L %%# in (1,1,4096) do set "st1=!st1!A"
call :strlen st1 len1
echo !len1!
set "st2="
For /L %%# in (1,1,4089) do set "st2=!st2!_"
call :strlen st2 len2
echo !len2!
set st3=!st1!!st2!
call :strlen st3 len3
echo !len3!
set /a l=len1+len2
echo calculate=!l!

goto :eof

: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


result:

Code: Select all

4096
4089
8191
calculate=8185


Einstein1969

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: StrLen +Set Help

#2 Post by jeb » 17 Oct 2013 00:11

Hi einstein1969,

you found the line length limitation.
Each line in batch can only be 8191 characters long (more or less).
So this produces also the result that the content of a variable can't be longer than this limit.

jeb

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: StrLen +Set Help

#3 Post by einstein1969 » 17 Oct 2013 03:58

jeb wrote:Hi einstein1969,

you found the line length limitation.
Each line in batch can only be 8191 characters long (more or less).
So this produces also the result that the content of a variable can't be longer than this limit.

jeb


Thanks jeb for replay.

But... where is the problem?

result:

Code: Select all

4096
4089
8191
calculate=8185
Size of st3.dat is 8185.

17/10/2013  11:56             8.185 st3.dat


code:

Code: Select all

@echo off & setlocal enabledelayedExpansion


set "st1="
For /L %%# in (1,1,4096) do set "st1=!st1!A"
call :strlen st1 len1
echo !len1!
set "st2="
For /L %%# in (1,1,4089) do set "st2=!st2!_"
call :strlen st2 len2
echo !len2!
set st3=!st1!!st2!
call :strlen st3 len3
echo !len3!
set /a l=len1+len2
echo calculate=!l!
<nul set/p "=!st3!">st3.dat
for %%# in (st3.dat) do echo Size of %%# is %%~z#.
echo(
dir st3.dat|find "st3.dat"

goto :eof

: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


Einstein1969

jeb
Expert
Posts: 1055
Joined: 30 Aug 2007 08:05
Location: Germany, Bochum

Re: StrLen +Set Help

#4 Post by jeb » 17 Oct 2013 06:04

einstein1969 wrote:But... where is the problem?


It's in the strlen function.

Code: Select all

set "str=A!%~1!"


As the complete line (complete without the length of the command) needs to be less than 8191 characters, it creates an unchanged str variable if your content reaches a length of 8185.

As 8185+lengthof("str=A")+2quotes = 8192 characters, it exceeds.
Then the complete line is dropped.
So <str> will be unchanged, if you set before you start your program

Code: Select all

set str=X

You get a string length of 1 at this point.

To avoid this change the strlen function

Code: Select all

(set s=A!%~1!)

The parenthesis are not counted to the line length, but it avoids invisble spaces.

But even this can only handle strings up to 8188 characters, the other three characters are needed by "s=A"



If you change the variable name to **t** only then you get a string that is two characters longer.

einstein1969
Expert
Posts: 961
Joined: 15 Jun 2012 13:16
Location: Italy, Rome

Re: StrLen +Set Help

#5 Post by einstein1969 » 17 Oct 2013 15:00

thanks jeb.

I have modified with parentesis () e other stuff

and have incremented one by one char

this is the result:

Code: Select all

E:\x264\provini>tmp4
s=X
SESSIONNAME=Console
SystemDrive=C:
SystemRoot=C:\Windows

strlen[st1]:4096

strlen[st2]:4091
strlen[s]:8187
calculate=8187
Size of s.dat is 8187.

17/10/2013  18:43             8.187 s.dat

Size of s.dat is 8189 [+2 for CRLF].

17/10/2013  18:43             8.189 s.dat

strlen[st2]:4092
strlen[s]:8188
calculate=8188
Size of s.dat is 8188.

17/10/2013  18:43             8.188 s.dat

Size of s.dat is 8190 [+2 for CRLF].

17/10/2013  18:43             8.190 s.dat

strlen[st2]:4093
strlen[s]:8188
calculate=8189
Size of s.dat is .

File non trovato
Impossibile trovare E:\x264\provini\s.dat

Size of s.dat is 8191 [+2 for CRLF].

17/10/2013  18:43             8.191 s.dat  <----------- why this increment?

strlen[st2]:4094
strlen[s]:8188
calculate=8190
Size of s.dat is .

File non trovato
Impossibile trovare E:\x264\provini\s.dat

Size of s.dat is 8191 [+2 for CRLF].

17/10/2013  18:43             8.191 s.dat

E:\x264\provini>


new code:

Code: Select all

@echo off & setlocal enabledelayedExpansion

set s

echo(
set "st1="
For /L %%# in (1,1,4096) do set "st1=!st1!A"
call :strlen st1 len1
echo strlen[st1]:!len1!

for %%_ in (4091 4092 4093 4094) do (

echo(
set "st2="
For /L %%# in (1,1,%%_) do set "st2=!st2!_"
call :strlen st2 len2
echo strlen[st2]:!len2!

set s=!st1!!st2!
call :strlen s len3
echo strlen[s]:!len3!

rem check
set /a l=len1+len2
echo calculate=!l!

rem other check
<nul set/p "=!s!">s.dat
for %%# in (s.dat) do echo Size of %%# is %%~z#.
echo(
dir s.dat|find "s.dat"
del s.dat

echo(
echo(!s!>s.dat
for %%# in (s.dat) do echo Size of %%# is %%~z# [+2 for CRLF].
echo(
dir s.dat|find "s.dat"
del s.dat

)

goto :eof

: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 s=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 "!s:~%%B,1!"=="" set /a "len&=~1<<%%A"
    )
)
( ENDLOCAL & REM RETURN VALUES
    IF "%~2" NEQ "" SET /a %~2=%len%
)
EXIT /b



I can't understand the

So <str> will be unchanged, if you set before you start your program

Code: Select all

set str=X


You get a string length of 1 at this point.


and this is even more obscure to me ... can you do me a practical example?
If you change the variable name to **t** only then you get a string that is two characters longer.


and one thing on the double quotes:
Are necessary to ensure the content or use only to avoid any errors in space characters

Also I would put the character "A" at the end. Because it is put at the beginning?



Einstein1969

hiUser
Posts: 1
Joined: 18 Sep 2015 02:13

Re: StrLen +Set Help

#6 Post by hiUser » 18 Sep 2015 02:23

I modified the code(removing the quotes):

Code: Select all

: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%
)


and it works perfectly fine with spaces and long strings.

or is there a use for the quotes??? :?

ShadowThief
Expert
Posts: 1166
Joined: 06 Sep 2013 21:28
Location: Virginia, United States

Re: StrLen +Set Help

#7 Post by ShadowThief » 18 Sep 2015 09:44

hiUser wrote:I modified the code(removing the quotes):

Code: Select all

: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%
)


and it works perfectly fine with spaces and long strings.

or is there a use for the quotes??? :?

Either I'm blind, or you didn't remove any quotes. The only differences between your post and the one before it are the variable name and removing the parentheses around the initial set statement.

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: StrLen +Set Help

#8 Post by penpen » 18 Sep 2015 11:37

If you need to compute the length of variables (up to the size of 8191) then you have to change the algorithm (don't create variables of problematic length).
In that case something like this may help you (currently untested):

Code: Select all

:strLen
(
   setlocal enableExtensions enableDelayedExpansion

   if "!%~1:~4095,1!" == "" (
      set "str=A!%~1!"
      set "len=0"
   ) else (
      set "str=A!%~1:~4096!"
      set "len=4096"
   )

   for %%A in (2048 1024 512 256 128 64 32 16 8 4 2 1) do if not "!str:~%%~A,1!" == "" (
      set /A "len+=%%~A"
      set "str=!str:~%%~A!"
   )
)
(
   endlocal
   if "%~2" == "" (
      echo(%len%
   ) else (
      set /a "%~2=%len%"
   )
)
exit /b

@ShadowThief: I think hiUser refered to the original source.


penpen

ShadowThief
Expert
Posts: 1166
Joined: 06 Sep 2013 21:28
Location: Virginia, United States

Re: StrLen +Set Help

#9 Post by ShadowThief » 18 Sep 2015 12:53

Ah. In that particular instance, no; the quotes there are used to ensure that there are no hidden spaces after A!%~1! that could give an incorrect result.

Post Reply