strLen boosted

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

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

Re: strLen boosted

#46 Post by einstein1969 » 20 Jul 2025 06:29

The last one I made isn't the fastest, but a compressed version that uses the previous fast one.

Here's the fast one (it took me a few days to create the macro on one line like you did; I'm going crazy.)

Code: Select all

:: make sure we are in the spotlight:
:: run as administrator for realtime priority!!!
:: /affinity 0x3  = 2 core/thread
@if "%~1"=="" start /realtime conhost "%~f0" 1&exit /b
@echo off & setlocal DisableDelayedExpansion

:: 8190
set str1=^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxX

:: 6000
set "str2=%str1:~,6000%"
:: 4000
set "str3=%str1:~,4000%"
:: 2000
set "str4=%str1:~,2000%"
:: 1000
set "str5=%str1:~,1000%"
:: 200
set "str6=%str1:~,200%"
:: 10
set "str7=%str1:~,10%"

call :initTimediff

:: uncomment this to get the evidence that it also works with delayed expansion enabled
::setlocal EnableDelayedExpansion

echo(
echo ~~~~~~~~~~~~~~~~~~~~
echo Steffen
call :initStrLenSteffen
echo Functional test
call :func_test
rem call :test str1
rem call :test str2
rem call :test str3
rem call :test str4
rem call :test str5
rem call :test str6
rem call :test str7

echo(
echo ~~~~~~~~~~~~~~~~~~~~
echo Francesco
call :initStrLenFrancesco
echo Functional test
call :func_test
rem call :test str1
rem call :test str2
rem call :test str3
rem call :test str4
rem call :test str5
rem call :test str6
rem call :test str7

echo(
echo ~~~~~~~~~~~~~~~~~~~~
echo jeb
echo Functional test
call :func_test
rem call :test str1
rem call :test str2
rem call :test str3
rem call :test str4
rem call :test str5
rem call :test str6
rem call :test str7

echo(
echo ~~~~~~~~~~~~~~~~~~~~
echo final
call :initStrLen
echo Functional test
call :func_test
call :test str1
call :test str2
call :test str3
call :test str4
call :test str5
call :test str6
call :test str7

echo(
echo ~~~~~~~~~~~~~~~~~~~~
echo final 2
call :initStrLen2
echo Functional test
call :func_test
call :test str1
call :test str2
call :test str3
call :test str4
call :test str5
call :test str6
call :test str7


pause
exit /b



::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLenSteffen
setlocal DisableDelayedExpansion

:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
set strLen=for %%- in (1 2) do if %%-==2 (^
setlocal EnableDelayedExpansion^&for /f "tokens=1,2" %%. in ("^^!`^^!") do ^
set #=0^&(if defined %%~. (if ` neq ^^!%%~.:~4095^^!` ^
(set $=^^!%%~.:~4096^^!F^&set /a #+=4096) else set $=^^!%%~.^^!F)^&^
(for %%# in (2048 1024 512 256) do if ` neq ^^!$:~%%#^^!` ^
set $=^^!$:~%%#^^!^&set /a #+=%%#)^&set $=^^!$^^!^
EDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
333333333333333322222222222222221111111111111111^&^
set /a #+=0x^^!$:~511,1^^!^^!$:~255,1^^!)^&^
for %%# in (^^!#^^!) do endlocal^&set %%~/=%%#) else set `=

endlocal&set "strLen=%strLen%"
if !!# neq # set "strLen=%strLen:^^=%"
goto :eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLenFrancesco
setlocal DisableDelayedExpansion

set strLen=for %%- in (1 2) do if %%-==2 (^
setlocal EnableDelayedExpansion^&for /f "tokens=1,2" %%. in ("^^!`^^!") do ^
set #=0^&(if defined %%~. (if ` neq ^^!%%~.:~4095^^!` ^
(set $=^^!%%~.:~4096^^!^&set #=4096) else set $=^^!%%~.^^!)^&^
(if defined $ if "^^!$:~255,1^^!" neq "" ^
set "t=^^!$:~3839,1^^!^^!$:~3583,1^^!^^!$:~3327,1^^!^^!$:~3071,1^^!^^!$:~2815,1^^!^^!$:~2559,1^^!^^!$:~2303,1^^!^^!$:~2047,1^^!^^!$:~1791,1^^!^^!$:~1535,1^^!^^!$:~1279,1^^!^^!$:~1023,1^^!^^!$:~767,1^^!^^!$:~511,1^^!^^!$:~255,1^^!FEDCBA9876543210"^&^
set /a "#+=t=0x^^!t:~15,1^^!*256"^&for %%# in (^^!t^^!) do set "$=^^!$:~%%#^^!")^&^
if defined $ ^
set "t=^^!$:~239,1^^!^^!$:~223,1^^!^^!$:~207,1^^!^^!$:~191,1^^!^^!$:~175,1^^!^^!$:~159,1^^!^^!$:~143,1^^!^^!$:~127,1^^!^^!$:~111,1^^!^^^!$:~95,1^^!^^!$:~79,1^^!^^!$:~63,1^^!^^!$:~47,1^^!^^!$:~31,1^^!^^!$:~15,1^^!FEDCBA9876543210"^&^
set /a "t=0x^^!t:~15,1^^!*16"^&for %%# in (^^!t^^!) do ^
set "$=^^!$:~%%#^^!FEDCBA9876543210"^&set /a "#+=t+0x^^!$:~15,1^^!")^&^
for %%# in (^^!#^^!) do endlocal^&set %%~/=%%#) else set `=

endlocal&set "strLen=%strLen%"
if !!# neq # set "strLen=%strLen:^^=%"
goto :eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLenJeb
::: Macro to define macros without knowing the delayed expansion mode
::: Usage:
::: %$lib.macrodefine.free% set my_macro=...
:::
::: Reserved FOR variables:
::: %%! - contains one !
::: %%^ - results into one caret, attention read the other comments!
:::
::: While defining a new macro:
::: - Each bang ! has to be changed to %%!   regex-replace: (?<!%%)! -> %%!

::: - Each caret ^ has to be changed to %%^^ regex-replace: (?<!%%)\^ -> %%^^
::: - If carets are inside quotes replace them only with %%^  .
::: - But be careful only replace carets that should be placed in the macro itself
::: - Carets can also be used for escaping special chars in the definition phase, like ^&, ^<, ^|, ^"
FOR /F "tokens=1 delims== " %%! in ("!=! ^^^!") DO ^
FOR /F %%^^ in ("^ ^^^^%%!=%%!") DO ^
set ^"$lib.macrodefine.free=@FOR /F "tokens=1 delims== " %%%%! in ("%%!=%%! %%^%%^%%^%%!") DO ^
@FOR /F %%%%^^%%^^ in ("%%^ %%^%%^%%^%%^%%^%%!=%%^%%!") DO @"

REM *** Defining a line feed for usage while defining macros
(set ^"$\n=^^^
%=empty=%
)
@REM %$lib.macrodefine.free% echo "Test1: %%! and %%^ --"
@REM %$lib.macrodefine.free% echo  Test2: %%! and %%^^ --

:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
%$lib.macrodefine.free% set strLen=for %%# in (1 2) do if %%#==2 ( %$\n%
    for /f "tokens=1,2" %%1 in ("%%!args%%!") do ( %$\n%
        set L=0 %$\n%
        if defined %%~1 ( %$\n%
            if "" neq "%%!%%~1:~255%%!" ( %$\n%
                for %%# in (4095 2047 1023 511 255) do ( %$\n%
                    set /a t=L+%%# %$\n%
                    for %%T in (%%!t%%!) do ( %$\n%
                        if "" neq "%%!%%~1:~%%T%%!" set /a L=%%T+1 %$\n%
                    ) %$\n%
                ) %$\n%
            ) %$\n%
            for %%# in (%%!L%%!) do ( %$\n%
                set ^"$=%%!%%~1:~%%#%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
333333333333333322222222222222221111111111111111^" %$\n%
                set /a L+=0x%%!$:~511,1%%!%%!$:~255,1%%! %$\n%
            ) %$\n%
        ) %$\n%
        for %%# in (%%!L%%!) do ( %$\n%
            endlocal %$\n%
            set %%~2=%%# %$\n%
        ) %$\n%
    ) %$\n%
 ) else setlocal EnableDelayedExpansion ^& set args=

goto :eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen Final
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set strLen=^
for /f "tokens=2" %%? in ("%%!%%! D E") do for %%. in (1 2) do if %%.==2 (^
  for /f "tokens=1,2" %%1 in ("%%!$args%%!") do (^
    set "$L=0"^&^
    (if defined %%~1^
      (if "" neq "%%!%%~1:~255%%!"^
        (if "" neq "%%!%%~1:~4095%%!"^
          (set "$=%%!%%~1:~4096%%!"^&set "$L=4096") else set "$=%%!%%~1%%!"^
        )^&^
        (if defined $^
          set ^"$scale=^
%%!$:~255,1%%!%%!$:~511,1%%!%%!$:~767,1%%!%%!$:~1023,1%%!%%!$:~1279,1%%!^
%%!$:~1535,1%%!%%!$:~1791,1%%!%%!$:~2047,1%%!%%!$:~2303,1%%!%%!$:~2559,1%%!^
%%!$:~2815,1%%!%%!$:~3071,1%%!%%!$:~3327,1%%!%%!$:~3583,1%%!%%!$:~3839,1%%!^
FEDCBA9876543210^"^&^
          set /a "$L+=0x%%!$scale:~15,1%%!*256"^
        )^
      )^&^
      for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
333333333333333322222222222222221111111111111111^"^&^
      set /a "$L+=0x%%!$:~511,1%%!%%!$:~255,1%%!"^
    )^&^
    for %%# in (%%!$L%%!) do (if %%?==D endlocal)^&set "%%~2=%%#"^
  )^
) else (if %%?==D setlocal EnableDelayedExpansion)^&set $args=

goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2 final 2
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set strLen=^
for /f "tokens=2" %%? in ("%%!%%! D E") do for %%. in (1 2) do if %%.==2 (^
  for /f "tokens=1,2" %%1 in ("%%!$args%%!") do (^
    if defined %%~1 ^
      ((if "" neq "%%!%%~1:~255%%!"^
	(^
        (if "" neq "%%!%%~1:~4095%%!"^
          (set "$=%%!%%~1:~4095%%!") else set "$=%%!%%~1%%!"^
        )^&^
          set ^"$scale=^
%%!$:~255,1%%!%%!$:~511,1%%!%%!$:~767,1%%!%%!$:~1023,1%%!%%!$:~1279,1%%!^
%%!$:~1535,1%%!%%!$:~1791,1%%!%%!$:~2047,1%%!%%!$:~2303,1%%!%%!$:~2559,1%%!^
%%!$:~2815,1%%!%%!$:~3071,1%%!%%!$:~3327,1%%!%%!$:~3583,1%%!%%!$:~3839,1%%!^
FEDCBA9876543210^"^&^
	(^
          if "" neq "!%%~1:~4095!" ( set /a "$L=0x!$scale:~15,1!*256+4095") else set /a "$L=0x%%!$scale:~15,1%%!*256"^
        )^
        ) else set "$L=0"^
      )^&^
      for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
333333333333333322222222222222221111111111111111^"^&^
      for %%# in ("%%!$L%%!+0x%%!$:~511,1%%!%%!$:~255,1%%!") do (if %%?==D endlocal)^&set /A "%%~2=%%#"^
     ) else (if %%?==D endlocal)^&set "%%~2=0"^
  )^
) else (if %%?==D setlocal EnableDelayedExpansion)^&set $args=
goto :eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:initTimediff
for /f %%! in ("! ^! ^^^!") do ^
set timediff=for /l %%# in (1 1 2) do if %%#==2 for /f "tokens=2" %%$ in ("%%!%%! 1 0") do ((if 1==%%$ setlocal EnableDelayedExpansion)^&for /f "tokens=1-3" %%- in ("%%!_i_%%!") do (set "_t1_=%%!%%~-: =0%%!"^&set "_t2_=%%!%%~.: =0%%!"^&^
set /a "_d_=(8640000+(((1%%!_t2_:~,2%%!*60+1%%!_t2_:~3,2%%!)*60+1%%!_t2_:~6,2%%!)*100+1%%!_t2_:~-2%%!-36610100)-(((1%%!_t1_:~,2%%!*60+1%%!_t1_:~3,2%%!)*60+1%%!_t1_:~6,2%%!)*100+1%%!_t1_:~-2%%!-36610100))%%8640000,_o_=100000000+(_d_%%100),_d_/=100,_o_+=(_d_%%60)*100,_d_/=60,_o_+=(_d_%%60)*10000+_d_/60*1000000"^&^
set "_o_=%%!_o_:~1,2%%!:%%!_o_:~3,2%%!:%%!_o_:~5,2%%!.%%!_o_:~-2%%!"^&for /f %%' in ("%%!_o_%%!") do ((if 1==%%$ endlocal)^&if "%%~/"=="" (echo %%') else set "%%~/=%%'"))) else set _i_=
goto :eof

:test
echo(

setlocal EnableDelayedExpansion
set len=
for /l %%i in (1 1 4) do (
  set t1=!time!
  for /l %%i in (1 1 5000) do %strLen% %1 len
  set t2=!time!
  %timediff% t1 t2 diff
  echo !diff!
)
echo Check: len=!len!
endlocal
goto :eof
:::::::::::::::::::::::::::::::::::::::::::::::::...
:func_test
	setlocal EnableDelayedExpansion
	set "str="
	for /L %%L in (0,1,8185) do (
		%strLen% str len
		set "str=!str!X"
		title %%L !len!
		if !len! neq %%L pause
	)
goto :eof
result:

Code: Select all

~~~~~~~~~~~~~~~~~~~~
final
Functional test
OK.

00:00:04.46
00:00:04.51
00:00:04.51
00:00:04.52
Check: len=8190

00:00:04.12
00:00:04.18
00:00:04.17
00:00:04.27
Check: len=6000

00:00:03.89
00:00:03.95
00:00:03.95
00:00:03.95
Check: len=4500

00:00:03.82
00:00:04.00
00:00:04.06
00:00:03.89
Check: len=2000

00:00:03.73
00:00:03.76
00:00:03.76
00:00:03.75
Check: len=1000

00:00:02.63
00:00:02.68
00:00:02.68
00:00:02.68
Check: len=200

00:00:02.60
00:00:02.68
00:00:02.68
00:00:02.67
Check: len=10

~~~~~~~~~~~~~~~~~~~~
final 2
Functional test
OK.

00:00:03.97
00:00:04.03
00:00:04.03
00:00:04.03
Check: len=8190

00:00:03.65
00:00:03.72
00:00:03.70
00:00:03.71
Check: len=6000

00:00:03.40
00:00:03.47
00:00:03.45
00:00:03.46
Check: len=4500

00:00:03.54
00:00:03.59
00:00:03.66
00:00:03.59
Check: len=2000

00:00:03.39
00:00:03.45
00:00:03.47
00:00:03.46
Check: len=1000

00:00:02.55
00:00:02.61
00:00:02.61
00:00:02.61
Check: len=200

00:00:02.55
00:00:02.60
00:00:02.60
00:00:02.60
Check: len=10
Premere un tasto per continuare . . .

Code: Select all

5000 cycles
::      | final  |  final2 |
::------+--------+---------+
:: 8190 | 04.51  |  04.03  |
:: 6000 | 04.17  |  03.71  |
:: 4500 | 03.95  |  03.46  |
:: 2000 | 04.00  |  03.60  |
:: 1000 | 03.76  |  03.46  |
::  200 | 02.68  |  02.61  |
::   10 | 02.68  |  02.60  |

Code: Select all

10000 cycles
::      | final  |  final2 |
::------+--------+---------+
:: 8190 | 09.02  |  08.06  |
:: 6000 | 08.27  |  07.40  |
:: 4500 | 07.81  |  06.95  |
:: 2000 | 07.70  |  07.21  |
:: 1000 | 07.40  |  06.94  |
::  200 | 05.34  |  05.26  |
::   10 | 05.31  |  05.24  |
PS. For the "Realtime" prioticity I used the "run as administrator" otherwise it gives you "high"

I also wanted to ask you what difference there is between calling "cmd" or "conhost".

aGerman
Expert
Posts: 4743
Joined: 22 Jan 2010 18:01
Location: Germany

Re: strLen boosted

#47 Post by aGerman » 20 Jul 2025 07:34

Cool :D If I take the latest code I posted, it comes pretty much down to the same results. Your's is still slightly faster but lacks the 8191 upper limit. Not really important though.
PS. For the "Realtime" prioticity I used the "run as administrator" otherwise it gives you "high"
You're right. "High" does still sufficiently avoid high value deviations. That's actually the point why I use a higher priority. It doesn't reflect the absolute values that would be measured with normal priority. However, absolute values can't be compared between different computers anyway.
I also wanted to ask you what difference there is between calling "cmd" or "conhost".
I tried to save some resources. I've set Terminal the default to run console apps on my machine. Explicitly running conhost avoids some overhead, taking into consideration that we want to run it with higher priority. Conhost spawns the cmd.exe process for us (not exactly what actually happens, only to keep it short). If you have conhost set the default, it just works the other way around, i.e. cmd spawns the conhost process. There isn't one without the other. Even Terminal runs a hidden conhost window (ConPTY) for our cmd process behind the scenes.
All that doesn't influence the measured values in my tests though.

Steffen

Aacini
Expert
Posts: 1932
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: strLen boosted

#48 Post by Aacini » 21 Jul 2025 09:16

May I suggest a simple modification that may speed up the process when there are setlocal/endlocal and frequent environment updates? Just define a "filler" variable at end of the environment before the setlocal and then, inside the routine that update the environment, release such a variable:

Code: Select all

rem Define a filler variable at environment end:
set "zzzzzz=Enough space for environment movements"

rem Do the setlocal
setlocal

rem Free the filler space
set "zzzzzz="

rem Do environment movements...
set "var=..."

endlocal
The filler variable may have the same name of the first variable used in the routine (so it is not necesary to release it), but it is important that such a variable be defined at end of the environment...

Antonio

aGerman
Expert
Posts: 4743
Joined: 22 Jan 2010 18:01
Location: Germany

Re: strLen boosted

#49 Post by aGerman » 21 Jul 2025 17:00

Nice idea, Antonio. So, what you suggest could look like so for testing purposes?

Code: Select all

:: make sure we are in the spotlight:
@if "%~1"=="" start /realtime conhost "%~f0" 1&exit /b
@echo off &setlocal EnableDelayedExpansion

set str=^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

call :initTimediff

for /l %%n in (1 1 20) do (
  set "foo="     &call :test 1
  set "foo=!str!"&call :test 2
)

pause
goto :eof

:initTimediff
for /f %%! in ("! ^! ^^^!") do ^
set timediff=for /l %%# in (1 1 2) do if %%#==2 for /f "tokens=2" %%$ in ("%%!%%! 1 0") do ((if 1==%%$ setlocal EnableDelayedExpansion)^&for /f "tokens=1-3" %%- in ("%%!_i_%%!") do (set "_t1_=%%!%%~-: =0%%!"^&set "_t2_=%%!%%~.: =0%%!"^&^
set /a "_d_=(8640000+(((1%%!_t2_:~,2%%!*60+1%%!_t2_:~3,2%%!)*60+1%%!_t2_:~6,2%%!)*100+1%%!_t2_:~-2%%!-36610100)-(((1%%!_t1_:~,2%%!*60+1%%!_t1_:~3,2%%!)*60+1%%!_t1_:~6,2%%!)*100+1%%!_t1_:~-2%%!-36610100))%%8640000,_o_=100000000+(_d_%%100),_d_/=100,_o_+=(_d_%%60)*100,_d_/=60,_o_+=(_d_%%60)*10000+_d_/60*1000000"^&^
set "_o_=%%!_o_:~1,2%%!:%%!_o_:~3,2%%!:%%!_o_:~5,2%%!.%%!_o_:~-2%%!"^&for /f %%' in ("%%!_o_%%!") do ((if 1==%%$ endlocal)^&if "%%~/"=="" (echo %%') else set "%%~/=%%'"))) else set _i_=
goto :eof

:test
setlocal
set "foo="
set t1=%time%
for /l %%i in (1 1 20000) do set "x%1=%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i%%i" 
set t2=%time%
%timediff% t1 t2 diff
if %1==1 (echo %diff%) else (echo              %diff%)
endlocal
goto :eof
Result:

Code: Select all

00:00:00.79
             00:00:00.70
00:00:00.70
             00:00:00.69
00:00:00.70
             00:00:00.70
00:00:00.70
             00:00:00.72
00:00:00.70
             00:00:00.70
00:00:00.70
             00:00:00.70
00:00:00.70
             00:00:00.72
00:00:00.70
             00:00:00.69
00:00:00.70
             00:00:00.70
00:00:00.69
             00:00:00.70
00:00:00.70
             00:00:00.70
00:00:00.70
             00:00:00.69
00:00:00.72
             00:00:00.70
00:00:00.70
             00:00:00.69
00:00:00.69
             00:00:00.71
00:00:00.70
             00:00:00.70
00:00:00.68
             00:00:00.72
00:00:00.70
             00:00:00.70
00:00:00.69
             00:00:00.69
00:00:00.71
             00:00:00.70
Drücken Sie eine beliebige Taste . . .
The indented durations are those with a long "foo" variable set that is removed after setlocal. There doesn't seem any noticeable difference.
(The first test run takes always slightly longer, also if I change the order and call :test 2 before :test 1. Probably because of caching.)

I guess the assumption you made is that the memory allocated once doesn't shrink. That might be true. ^1)
However, my understanding is that always all environment variables (the entire multi-string that I mentioned previously) will be rewritten, regardless of the kind of the update (no matter if a variable is added or removed, no matter if a value is updated keeping the same length or having a different length, and no matter at what position the variable occurs in the list). I certainly have to do some more internet research to fully understand it though.

Steffen

EDIT:
^1) Yes, this is true. I wrote a little C app to see what happens. You can even look at the results in a live compilation on Compiler Explorer:
https://godbolt.org/z/4Tz9oEha3
As you can see, only after adding the ZZZ variable a new pointer is allocated. If the variable value is shortened or if a variable is removed, it is not necessary to allocate new memory and the pointer remains the same.

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

Re: strLen boosted

#50 Post by einstein1969 » 23 Jul 2025 01:23

Yes, what Antonio mentioned was used in that thread testing the performance of the set command, and in some cases there was a difference.

In the meantime, I added the limit to 8191. It lost a bit in the lower range, but I don't understand why; further testing is needed. There was also a bug with the $ variable that I had to fix. Now it seems good and fast.

Code: Select all

:: make sure we are in the spotlight:
:: run as administrator for realtime priorities, else you will get "high" priorities
:: /affinity 0x3  = 2 core/thread
@if "%~1"=="" start /realtime conhost "%~f0" 1&exit /b
@echo off & setlocal DisableDelayedExpansion

:: 8191
set str1=^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx^
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxX

:: 6000
set "str2=%str1:~,6000%"
:: 4000
set "str3=%str1:~,4500%"
:: 2000
set "str4=%str1:~,2000%"
:: 1000
set "str5=%str1:~,1000%"
:: 200
set "str6=%str1:~,200%"
:: 10
set "str7=%str1:~,10%"

call :initTimediff

:: uncomment this to get the evidence that it also works with delayed expansion enabled
:: setlocal EnableDelayedExpansion


call :initStrLenFinal
call :initStrLenFinal2


%strlen% str1 len
echo final : Check 8191 string =^> %len%
%strlen2% str1 len
echo final 2 : Check 8191 string =^> %len%

call :test-funz

:prest

call :test str1
call :test str2
call :test str3
call :test str4
call :test str5
call :test str6
call :test str7

pause

goto :eof


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLenFinal2 final 2 readable
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set strLen2=^
for /f "tokens=2" %%? in ("%%!%%! D E") do for %%. in (1 2) do if %%.==2 (^
%=   =% for /f "tokens=1,2" %%1 in ("%%!$args%%!") do for %%3 in (%%~1) do (^
%=			=% if defined %%3 (^
%=     				=% (^
%=					=% if "" neq "%%!%%3:~255%%!" (^
%=						=% if "" neq "%%!%%3:~4095%%!" (set "$=%%!%%3:~4096%%!") else set "$=%%!%%3%%!"^
%=						=% ) ^& (^
%=							=% if defined $ (^
%=         							=% set ^"$Scale=^
%=								=%%%!$:~255,1%%!%%!$:~511,1%%!%%!$:~767,1%%!%%!$:~1023,1%%!%%!$:~1279,1%%!^
%=		This zone is empty				=%%%!$:~1535,1%%!%%!$:~1791,1%%!%%!$:~2047,1%%!%%!$:~2303,1%%!%%!$:~2559,1%%!^
%=								=%%%!$:~2815,1%%!%%!$:~3071,1%%!%%!$:~3327,1%%!%%!$:~3583,1%%!%%!$:~3839,1%%!^
%=								=%FEDCBA9876543210^"^&^
%=								=% if "" neq "%%!%%3:~4095%%!" (^
%=									=% set /a "$L=0x%%!$Scale:~15,1%%!*256+4096"^
%=								=% ) else set /a "$L=0x%%!$Scale:~15,1%%!*256"^
%=							=% ) else if "" neq "%%!%%3:~4095%%!" set "$L=4096"^
%=       				=% ) else set "$L=0"^
%=				=% )^&^
%=				=% for %%# in (%%!$L%%!) do set ^"$=%%!%%3:~%%#%%!^
%=				=%FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
%=				=%FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
%=				=%FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
%=				=%FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
%=				=%FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
%=				=%BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
%=				=%7777777777777777666666666666666655555555555555554444444444444444^
%=				=%333333333333333322222222222222221111111111111111^"^&^
%=				=% for %%# in ("%%!$L%%!+0x%%!$:~511,1%%!%%!$:~255,1%%!") do (if %%?==D endlocal)^&set /A "%%~2=%%#"^
%=			=%) else (if %%?==D endlocal)^&set "%%~2=0"^
%==% )^
) else (if %%?==D setlocal EnableDelayedExpansion)^&set $args=
goto :eof


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLenFinal
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set strLen=^
for /f "tokens=2" %%? in ("%%!%%! D E") do for %%. in (1 2) do if %%.==2 (^
  for /f "tokens=1,2" %%1 in ("%%!$args%%!") do (^
    set "$L=0"^&^
    (if defined %%~1^
      (if "" neq "%%!%%~1:~255%%!"^
        (if "" neq "%%!%%~1:~4095%%!"^
          (set "$=%%!%%~1:~4096%%!"^&set "$L=4096") else set "$=%%!%%~1%%!"^
        )^&^
        (if defined $^
          set ^"$scale=^
%%!$:~255,1%%!%%!$:~511,1%%!%%!$:~767,1%%!%%!$:~1023,1%%!%%!$:~1279,1%%!^
%%!$:~1535,1%%!%%!$:~1791,1%%!%%!$:~2047,1%%!%%!$:~2303,1%%!%%!$:~2559,1%%!^
%%!$:~2815,1%%!%%!$:~3071,1%%!%%!$:~3327,1%%!%%!$:~3583,1%%!%%!$:~3839,1%%!^
FEDCBA9876543210^"^&^
          set /a "$L+=0x%%!$scale:~15,1%%!*256"^
        )^
      )^&^
      for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
333333333333333322222222222222221111111111111111^"^&^
      set /a "$L+=0x%%!$:~511,1%%!%%!$:~255,1%%!"^
    )^&^
    for %%# in (%%!$L%%!) do (if %%?==D endlocal)^&set "%%~2=%%#"^
  )^
) else (if %%?==D setlocal EnableDelayedExpansion)^& set $args=

goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:test

echo(
echo +--------+---------+----------+
echo I  len   I  final  I  final2  I
echo +--------+---------+----------+

setlocal EnableDelayedExpansion

set i=0
:loop
	set len=

	set t1=!time!
	for /l %%i in (1 1 15000) do %strLen% %1 len
	set t2=!time!
	%timediff% t1 t2 diff
	set/p.="I  !len!	 I  !diff:~6!  "<nul

	set t1=!time!
	for /l %%i in (1 1 15000) do %strLen2% %1 len
	set t2=!time!
	%timediff% t1 t2 diff
	echo I  !diff:~6!   I

	set /a i+=1
	if !i! lss 4 goto :loop

echo +--------+---------+----------+

endlocal
goto :eof

rem for /l %%i in (1 1 4) do (
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:test-funz

setlocal EnableDelayedExpansion

echo(
echo Functional test
echo(
set /p ".=final :"<nul

set "str="
for /L %%L in (0,1,8185) do (
		set len=
		%strLen% str len
		set "str=!str!X"
		title "%%L" "!len!"
		if "!len!" neq "%%L" echo error & pause
)
echo OK.

echo(
set /p ".=final 2:"<nul

set "str="
for /L %%L in (0,1,8185) do (
		set len=
		%strLen2% str len
		set "str=!str!X"
		title "%%L" "!len!"
		if "!len!" neq "%%L" echo error & pause
)
echo OK.

goto :eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:initTimediff
for /f %%! in ("! ^! ^^^!") do ^
set timediff=for /l %%# in (1 1 2) do if %%#==2 for /f "tokens=2" %%$ in ("%%!%%! 1 0") do ((if 1==%%$ setlocal EnableDelayedExpansion)^&for /f "tokens=1-3" %%- in ("%%!_i_%%!") do (set "_t1_=%%!%%~-: =0%%!"^&set "_t2_=%%!%%~.: =0%%!"^&^
set /a "_d_=(8640000+(((1%%!_t2_:~,2%%!*60+1%%!_t2_:~3,2%%!)*60+1%%!_t2_:~6,2%%!)*100+1%%!_t2_:~-2%%!-36610100)-(((1%%!_t1_:~,2%%!*60+1%%!_t1_:~3,2%%!)*60+1%%!_t1_:~6,2%%!)*100+1%%!_t1_:~-2%%!-36610100))%%8640000,_o_=100000000+(_d_%%100),_d_/=100,_o_+=(_d_%%60)*100,_d_/=60,_o_+=(_d_%%60)*10000+_d_/60*1000000"^&^
set "_o_=%%!_o_:~1,2%%!:%%!_o_:~3,2%%!:%%!_o_:~5,2%%!.%%!_o_:~-2%%!"^&for /f %%' in ("%%!_o_%%!") do ((if 1==%%$ endlocal)^&if "%%~/"=="" (echo %%') else set "%%~/=%%'"))) else set _i_=
goto :eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
edit : correct some errors

Code: Select all

final : Check 8191 string => 8191
final 2 : Check 8191 string => 8191

Functional test

final :OK.

final 2:OK.


--------+-------+--------+
len     | final | final2 |
--------+-------+--------+
8191    | 13.62 | 11.76  |
8191    | 13.62 | 11.72  |
8191    | 13.61 | 11.73  |
8191    | 13.62 | 11.74  |
--------+-------+--------+

--------+-------+--------+
len     | final | final2 |
--------+-------+--------+
6000    | 12.51 | 10.75  |
6000    | 12.56 | 10.68  |
6000    | 12.58 | 10.70  |
6000    | 12.57 | 10.65  |
--------+-------+--------+

--------+-------+--------+
len     | final | final2 |
--------+-------+--------+
4500    | 11.76 | 09.94  |
4500    | 11.90 | 09.97  |
4500    | 11.90 | 09.94  |
4500    | 11.93 | 09.89  |
--------+-------+--------+

--------+-------+--------+
len     | final | final2 |
--------+-------+--------+
2000    | 11.56 | 10.43  |
2000    | 11.61 | 10.43  |
2000    | 11.60 | 10.39  |
2000    | 11.59 | 10.38  |
--------+-------+--------+

--------+-------+--------+
len     | final | final2 |
--------+-------+--------+
1000    | 11.10 | 09.92  |
1000    | 11.17 | 09.98  |
1000    | 11.19 | 09.93  |
1000    | 11.13 | 09.99  |
--------+-------+--------+

--------+-------+--------+
len     | final | final2 |
--------+-------+--------+
200     | 07.92 | 07.41  |
200     | 07.98 | 07.45  |
200     | 07.98 | 07.41  |
200     | 08.00 | 07.44  |
--------+-------+--------+

--------+-------+--------+
len     | final | final2 |
--------+-------+--------+
10      | 07.86 | 07.36  |
10      | 07.91 | 07.34  |
10      | 07.92 | 07.35  |
10      | 07.94 | 07.39  |
--------+-------+--------+
Premere un tasto per continuare . . .
This is the non-macro version, which is even more readable. It should mirror the macro.

Code: Select all

:sub-strlen
	setlocal

	set "args=%1 %2"
	for /f "tokens=1,2" %%1 in ("!args!") do (
		(
			if defined %%~1 (
				(
					if "" neq "!%%~1:~255!" ((
					
						if "" neq "!%%~1:~4095!" (set "$=!%%~1:~4096!") else set "$=!%%~1!"
 						) & (
							if defined $ (

								set "$scale=!$:~255,1!!$:~511,1!!$:~767,1!!$:~1023,1!!$:~1279,1!!$:~1535,1!!$:~1791,1!!$:~2047,1!!$:~2303,1!!$:~2559,1!!$:~2815,1!!$:~3071,1!!$:~3327,1!!$:~3583,1!!$:~3839,1!FEDCBA9876543210"

								if "" neq "!%%~1:~4095!" (set /a "$L=0x!$scale:~15,1!*256+4096") else set /a "$L=0x!$scale:~15,1!*256"

							) else if "" neq "!%%~1:~4095!" (set "$L=4096") 

						)) else set "$L=0"
					)

     					for %%# in (!$L!) do set ^"$=!%%~1:~%%#!FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA999999999999999988888888888888887777777777777777666666666666666655555555555555554444444444444444333333333333333322222222222222221111111111111111^"

					for %%# in ("!$L!+0x!$:~511,1!!$:~255,1!") do endlocal & set /A "%%~2=%%#"
				
				) else endlocal & set "%%~2=0"
 		) 
 	)

goto :eof
Edit: I have a question

Code: Select all

set ^"$
Why is there a need to escape the double quote here while in other cases there is no need?

Francesco

aGerman
Expert
Posts: 4743
Joined: 22 Jan 2010 18:01
Location: Germany

Re: strLen boosted

#51 Post by aGerman » 23 Jul 2025 12:55

Definitely the fastest version we have so far. Well done :!:
May I suggest to consistently use spaces rather than tabs? The displayed tab width depends on editor settings and mixing them makes a mess with indentations.

Code: Select all

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen
:: Computes the number of resulting UTF-16 code units in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
               FOR %%H IN (FEDCBA9876543210) DO FOR /F %%! IN ("! ^! ^^^!") DO ^
set strLen=^
%==% for /f "tokens=2" %%? in ("%%!%%! D E") do for %%. in (1 2) do if %%.==2 (^
%=  =% for /f "tokens=1,2" %%1 in ("%%!$args%%!") do for %%3 in (%%~1) do (^
%=    =% if defined %%3 (^
%=      =% (^
%=        =% if "" neq "%%!%%3:~255%%!" (^
%=          =% if "" neq "%%!%%3:~4095%%!" (^
%=            =% set "$=%%!%%3:~4096%%!"^
%=          =% ) else set "$=%%!%%3%%!"^
%=        =% ) ^& (^
%=          =% if defined $ (^
%=            =% set ^"$Scale=^
%=             =%%%!$:~255,1%%!%%!$:~511,1%%!%%!$:~767,1%%!%%!$:~1023,1%%!^
%=             =%%%!$:~1279,1%%!%%!$:~1535,1%%!%%!$:~1791,1%%!%%!$:~2047,1%%!^
%=             =%%%!$:~2303,1%%!%%!$:~2559,1%%!%%!$:~2815,1%%!%%!$:~3071,1%%!^
%=             =%%%!$:~3327,1%%!%%!$:~3583,1%%!%%!$:~3839,1%%!%%H^"^&^
%=            =% if "" neq "%%!%%3:~4095%%!" (^
%=              =% set /a "$L=0x%%!$Scale:~15,1%%!*256+4096"^
%=            =% ) else set /a "$L=0x%%!$Scale:~15,1%%!*256"^
%=          =% ) else if "" neq "%%!%%3:~4095%%!" set "$L=4096"^
%=        =% ) else set "$L=0"^
%=      =% )^&^
%=      =% for %%# in (%%!$L%%!) do set ^"$=%%!%%3:~%%#%%!^
%=       =%%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H^
%=       =%FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
%=       =%BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
%=       =%7777777777777777666666666666666655555555555555554444444444444444^
%=       =%333333333333333322222222222222221111111111111111^"^&^
%=      =% for %%# in ("%%!$L%%!+0x%%!$:~511,1%%!%%!$:~255,1%%!") do (^
%=        =% (if %%?==D endlocal)^&set /A "%%~2=%%#"^
%=      =% )^
%=    =% ) else (if %%?==D endlocal)^&set "%%~2=0"^
%=  =% )^
%==% ) else (if %%?==D setlocal EnableDelayedExpansion)^&set $args=
goto :eof
Why is there a need to escape the double quote here while in other cases there is no need?
These carets will not be part of the macro. However, we need them for the parser to make sure line continuations work. This is because when viewed line by line, the quotes are not balanced, which would result in the caret at the end of the line belonging to a string literal.

Works because the closing quote is in the same line:
set "foo=bar"^&^
rem more code here

Doesn't work because carets are considered to be belonging to a string literal:
set "foo=^
bar"^&^
rem more code here

Works again:
set ^"foo=^
bar^"^&^
rem more code here

The parts with quotation semantics applied by the parser are marked in red.

Steffen
Last edited by aGerman on 03 Aug 2025 07:08, edited 1 time in total.
Reason: It does not compute the number of bytes as previously stated. Env. variables are stored UTF-16 encoded in the PEB and all we can count is code units (i.e., not code points, not grapheme clusters.)

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

Re: strLen boosted

#52 Post by einstein1969 » 24 Jul 2025 07:46

Thanks for the detailed and understandable explanation of escaping double quotes.

The rewritten code with spaces is a really good idea; I'll keep it in mind.

Francesco

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

Re: strLen boosted

#53 Post by einstein1969 » 02 Aug 2025 11:06

I add this variant made by T3rror, because it introduces intelligent ideas without losing speed.

Indeed it should be faster because it supposes the non -existence of double quotes around the variables
Hi Einst - I was looking over the final StrLen macro version you posted on dostips and noticed an easy little tweak to drop a redundant for loop.

%= =% for /f "tokens=1,2" %%1 in ("%%!$args%%!") do for %%3 in (%%~1) do (^
%= =% if defined %%3 (^

can be changed out to:

%= =% for /f "tokens=1,2" %%1 in ("%%!$args%%! $len") do if not "%%~2" == "" (^
%= =% if defined %%~1 (^


(using your editors replace function) also swap out instances of %%3 for %%~1.

The above also:

assumes a default return var $len if none is provided
fails silently if no arguments are provided

I know dropping the for %%3 in (%%~1) do loop will likely never be noticable in practical usage - especially with the work already put into optimizing this Macro, but I thought I'd share the suggestion all the same.
It was then corrected for use without double quotes and this is its version. Inserted an intelligent functionality and a little speed:

Code: Select all

@Echo off

Call :init.strlen

rem usage example
%strLen% computername
Set $len
Set computername
Endlocal & goto:eof

:init.strlen Macro
::  Computes the number of bytes in a string.
::
::  %strLen% <str> [len]
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length. Dafualts to $len if unsupplied
:: Strings of up to 8191 characters are supported.
   rem See: https://www.dostips.com/forum/viewtopic.php?p=71415#p71415
   rem optimized for best performance averaged across supported string lengths.

                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set strLen=^
for /f "tokens=2" %%? in ("%%!%%! D E") do for %%. in (1 2) do if %%.==2 (^
%=   =% for /f "tokens=1,2 delims= " %%1 in ("%%!$args%%! $len") do if not "%%~2" == "" (^
%=                        =% if defined %%1 (^
%=                                     =% (^
%=                                        =% if "" neq "%%!%%1:~255%%!" (^
%=                                                =% if "" neq "%%!%%1:~4095%%!" (set "$=%%!%%1:~4096%%!") else set "$=%%!%%1%%!"^
%=                                                =% ) ^& (^
%=                                                        =% if defined $ (^
%=                                                                 =% set ^"$Scale=^
%=                                                                =%%%!$:~255,1%%!%%!$:~511,1%%!%%!$:~767,1%%!%%!$:~1023,1%%!%%!$:~1279,1%%!^
%=                This zone is empty                                =%%%!$:~1535,1%%!%%!$:~1791,1%%!%%!$:~2047,1%%!%%!$:~2303,1%%!%%!$:~2559,1%%!^
%=                                                                =%%%!$:~2815,1%%!%%!$:~3071,1%%!%%!$:~3327,1%%!%%!$:~3583,1%%!%%!$:~3839,1%%!^
%=                                                                =%FEDCBA9876543210^"^&^
%=                                                                =% if "" neq "%%!%%1:~4095%%!" (^
%=                                                                        =% set /a "$L=0x%%!$Scale:~15,1%%!*256+4096"^
%=                                                                =% ) else set /a "$L=0x%%!$Scale:~15,1%%!*256"^
%=                                                        =% ) else if "" neq "%%!%%1:~4095%%!" set "$L=4096"^
%=                                       =% ) else set "$L=0"^
%=                                =% )^&^
%=                                =% for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
%= Leading space not supported    =%FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
%=                                =%FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
%=                                =%FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
%=                                =%FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
%=                                =%FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
%=                                =%BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
%=                                =%7777777777777777666666666666666655555555555555554444444444444444^
%=                                =%333333333333333322222222222222221111111111111111^"^&^
%=                                =% for %%# in ("%%!$L%%!+0x%%!$:~511,1%%!%%!$:~255,1%%!") do (if %%?==D endlocal)^&set /A "%%~2=%%#"^
%=                        =%) else (if %%?==D endlocal)^&set "%%~2=0"^
%==% )^
) else (if %%?==D setlocal EnableDelayedExpansion)^&set $args=
goto :eof

aGerman
Expert
Posts: 4743
Joined: 22 Jan 2010 18:01
Location: Germany

Re: strLen boosted

#54 Post by aGerman » 03 Aug 2025 04:46

(Only yesterday I deleted most of my test codes to make room on my desktop again :lol: No problem as I published it here as well...)

Hmm, I can't see any noticeable differences yet. Not even if I raise the number of iterations from 1,000 to 10,000. Perhaps If I increase them even more?

The updated macro still doesn't handle a quoted variable name correctly. I think you just didn't consistently use %%~1 (I saw %%1 in some places).
FWIW: I found the %%3 variable a neat idea as %%~1 will now trigger string manipulation in multiple places again.

Steffen

Edit: I updated the macro description in #51 to correctly tell what we are actually measuring in the macro. It's not necessarily the number of rendered glyphs. And it has also nothing to do with the number of bytes a string takes in our script code because env. variables are always converted into UTF-16 before they are stored in the process memory.

pieh-ejdsch
Posts: 257
Joined: 04 Mar 2014 11:14
Location: germany

Re: strLen boosted

#55 Post by pieh-ejdsch » 03 Aug 2025 12:56

Hi at all,

I've created a few versions so you can see why it runs faster or slower.

In any case, the final2 version isn't the fastest.
Ultimately, every unnecessary "if else" and every too many "set statements" and "variable calls" slows down the script.

But you can find a balance between these many possibilities.

I'm sorry that I've messed up your test script quite a bit.

But I've also shortened your time calculation a bit.

.....
The second column can safely be ignored, as this value is always too high.
An excerpt from it

Code: Select all


Check length str1 gtr 8190 X

~~~~~~~~~~~~~~~~~~~~
"513          TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
09.14
08.82
done
00.34  Check: len=8191
00.33  Check: len=6000
00.33  Check: len=4500
00.31  Check: len=1000
00.31  Check: len=600
00.26  Check: len=200
00.27  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"513o         TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
08.60
08.54
done
00.34  Check: len=8191
00.35  Check: len=6000
00.32  Check: len=4500
00.32  Check: len=1000
00.30  Check: len=600
00.30  Check: len=200
00.31  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"821          TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
08.14
08.12
done
00.32  Check: len=8191
00.31  Check: len=6000
00.31  Check: len=4500
00.28  Check: len=1000
00.23  Check: len=600
00.23  Check: len=200
00.26  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"821o         TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
07.76
07.88
done
00.29  Check: len=8191
00.28  Check: len=6000
00.30  Check: len=4500
00.30  Check: len=1000
00.26  Check: len=600
00.27  Check: len=200
00.28  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"912          TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
07.89
07.85
done
00.28  Check: len=8191
00.28  Check: len=6000
00.29  Check: len=4500
00.28  Check: len=1000
00.25  Check: len=600
00.24  Check: len=200
00.23  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"912o         TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
07.81
07.83
done
00.29  Check: len=8191
00.28  Check: len=6000
00.26  Check: len=4500
00.27  Check: len=1000
00.26  Check: len=600
00.26  Check: len=200
00.28  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"912i         TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
07.74
07.80
done
00.27  Check: len=8191
00.31  Check: len=6000
00.31  Check: len=4500
00.29  Check: len=1000
00.27  Check: len=600
00.26  Check: len=200
00.27  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"1           Final"
Functional test 0 ... 8189 + 8191 + presets + x380
09.05
09.03
done
00.36  Check: len=8191
00.34  Check: len=6000
00.33  Check: len=4500
00.35  Check: len=1000
00.31  Check: len=600
00.22  Check: len=200
00.22  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"2           Final"
Functional test 0 ... 8189 + 8191 + presets + x380
08.15
08.24
done
00.33  Check: len=8191
00.30  Check: len=6000
00.28  Check: len=4500
00.28  Check: len=1000
00.27  Check: len=600
00.20  Check: len=200
00.20  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"2o           TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
07.95
07.92
done
00.30  Check: len=8191
00.28  Check: len=6000
00.26  Check: len=4500
00.27  Check: len=1000
00.25  Check: len=600
00.26  Check: len=200
00.25  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"2i           TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
08.16
08.15
done
00.32  Check: len=8191
00.28  Check: len=6000
00.28  Check: len=4500
00.29  Check: len=1000
00.28  Check: len=600
00.27  Check: len=200
00.28  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"x334         TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
07.73
07.80
done
00.29  Check: len=8191
00.30  Check: len=6000
00.31  Check: len=4500
00.30  Check: len=1000
00.27  Check: len=600
00.27  Check: len=200
00.27  Check: len=10

~~~~~~~~~~~~~~~~~~~~
"x200         TEST"
Functional test 0 ... 8189 + 8191 + presets + x380
08.46
08.45
done
00.33  Check: len=8191
00.33  Check: len=6000
00.33  Check: len=4500
00.30  Check: len=1000
00.30  Check: len=600
00.29  Check: len=200
00.30  Check: len=10
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  x6080 I final1 I   2o   I   2i   I final1 I  x334  I  x200  I  912i  I  912o  I  821o  I  513o  I final2 I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  8191  I 04.17  I 02.53  I 02.22  I 02.99  I 02.71  I 03.17  I 02.64  I 02.63  I 02.70  I 03.10  I 02.52  I
I  8191  I 04.06  I 02.54  I 02.22  I 03.00  I 02.80  I 03.15  I 02.66  I 02.63  I 02.71  I 03.17  I 02.58  I
I  8191  I 04.15  I 02.50  I 02.18  I 02.98  I 02.69  I 03.21  I 02.72  I 02.71  I 02.73  I 03.16  I 02.64  I
I  8191  I 04.10  I 02.46  I 02.20  I 03.10  I 02.77  I 03.20  I 02.68  I 02.64  I 02.69  I 03.14  I 02.52  I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
....

+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  x6080 I final1 I   2o   I   2i   I final1 I  x334  I  x200  I  912i  I  912o  I  821o  I  513o  I final2 I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  600   I 04.10  I 02.54  I 02.24  I 03.03  I 02.76  I 03.21  I 02.65  I 02.64  I 02.71  I 03.12  I 02.53  I
I  600   I 04.07  I 02.48  I 02.21  I 03.01  I 02.73  I 03.14  I 02.68  I 02.65  I 02.76  I 03.16  I 02.59  I
I  600   I 04.07  I 02.52  I 02.23  I 03.10  I 02.73  I 03.17  I 02.68  I 02.63  I 02.78  I 03.12  I 02.54  I
I  600   I 04.09  I 02.47  I 02.20  I 03.02  I 02.71  I 03.19  I 02.70  I 02.77  I 02.72  I 03.10  I 02.58  I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+

+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  x6080 I final1 I   2o   I   2i   I final1 I  x334  I  x200  I  912i  I  912o  I  821o  I  513o  I final2 I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  200   I 04.12  I 02.48  I 02.21  I 02.99  I 02.76  I 03.15  I 02.64  I 02.64  I 02.69  I 03.09  I 02.56  I
I  200   I 04.04  I 02.48  I 02.27  I 03.05  I 02.77  I 03.15  I 02.82  I 02.70  I 02.74  I 03.14  I 02.65  I
I  200   I 04.12  I 02.56  I 02.26  I 03.03  I 02.72  I 03.12  I 02.64  I 02.64  I 02.70  I 03.12  I 02.55  I
I  200   I 04.09  I 02.46  I 02.19  I 03.00  I 02.71  I 03.20  I 02.67  I 02.62  I 02.70  I 03.17  I 02.56  I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+

+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  x6080 I final1 I   2o   I   2i   I final1 I  x334  I  x200  I  912i  I  912o  I  821o  I  513o  I final2 I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  10    I 04.06  I 02.49  I 02.19  I 03.02  I 02.72  I 03.16  I 02.65  I 02.63  I 02.77  I 03.10  I 02.55  I
I  10    I 04.03  I 02.46  I 02.19  I 02.99  I 02.69  I 03.11  I 02.72  I 02.72  I 02.70  I 03.11  I 02.54  I
I  10    I 04.06  I 02.45  I 02.22  I 03.00  I 02.74  I 03.15  I 02.72  I 02.68  I 02.70  I 03.14  I 02.54  I
I  10    I 03.99  I 02.46  I 02.26  I 03.05  I 02.75  I 03.10  I 02.66  I 02.68  I 02.76  I 03.10  I 02.53  I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+

Random 1/20
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  x6080 I final1 I   2o   I   2i   I final1 I  x334  I  x200  I  912i  I  912o  I  821o  I  513o  I final2 I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  3525  I 04.19  I 02.54  I 02.28  I 03.18  I 02.89  I 03.22  I 02.71  I 02.74  I 02.85  I 03.18  I 02.65  I
I  3525  I 04.26  I 02.64  I 02.28  I 03.10  I 02.76  I 03.22  I 02.77  I 02.73  I 02.75  I 03.13  I 02.58  I
I  3525  I 04.15  I 02.54  I 02.23  I 03.09  I 02.75  I 03.15  I 02.68  I 02.68  I 02.75  I 03.15  I 02.57  I
I  3525  I 04.13  I 02.54  I 02.24  I 03.13  I 02.78  I 03.18  I 02.72  I 02.68  I 02.74  I 03.18  I 02.60  I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+

Random 2/20
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  x6080 I final1 I   2o   I   2i   I final1 I  x334  I  x200  I  912i  I  912o  I  821o  I  513o  I final2 I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+
I  1584  I 04.10  I 02.52  I 02.28  I 03.08  I 02.74  I 03.15  I 02.65  I 02.65  I 02.75  I 03.14  I 02.57  I
I  1584  I 04.09  I 02.65  I 02.25  I 03.06  I 02.72  I 03.16  I 02.67  I 02.66  I 02.74  I 03.24  I 02.58  I
I  1584  I 04.21  I 02.54  I 02.24  I 03.03  I 02.73  I 03.15  I 02.67  I 02.67  I 02.73  I 03.14  I 02.60  I
I  1584  I 04.09  I 02.52  I 02.24  I 03.06  I 02.74  I 03.18  I 02.72  I 02.67  I 02.78  I 03.24  I 02.61  I
+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+--------+

Code: Select all

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: make sure we are in the spotlight:
:: run as administrator for realtime priorities, else you will get "high" priorities
:: /affinity 0x3  = 2 core/thread
@if "%~1"=="" start /realtime conhost "%~f0" 1&exit /b
@echo off & setlocal DisableDelayedExpansion

prompt $G$S
:reduceEnvironment -- remove unnecessary variables
for /f "tokens=1-2 delims=;" %%i in ("cmd.exe;.") do (
  for /f "delims==-" %%i in ('2^>nul set') do set "%%i="
  set "COMSPEC=%COMSPEC%"
  set "Path=%%~dp$PATH:i"
  set "PATHEXT=%PATHEXT%"
  set "prompt=$G$S"
  set "temp=%temp%"
  set "windir=%windir%"
)

:: 8191
 rem 16 32 64  128  256  512  1024 2048 4096
call call call call call call call call call set "x=^^^^^^^^X"
set "x=%x:~1%"
set str1=^
%x:^=xx%
echo(
echo Check length str1 gtr 8190 %str1:~8190%


:: 6000
set "str2=%str1:~,6000%"
:: 4000
set "str3=%str1:~,4500%"
:: 1000
set "str4=%str1:~,1000%"
:: 600
set "str5=%str1:~,600%"
:: 200
set "str6=%str1:~,200%"
:: 10
set "str7=%str1:~,10%"

call :initTimediff

:: uncomment this to get the evidence that it also works with delayed expansion enabled
:: setlocal EnableDelayedExpansion
goto :BeginTestOld



::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:BeginTestOld
set /a times_func=2
set /a times_test=380
for %%A in (
 "513          TEST"
 "513o         TEST"
 "821          TEST"
 "821o         TEST"
 "912          TEST"
 "912o         TEST"
 "912i         TEST"
 "1           Final"
 "2           Final"
 "2o           TEST"
 "2i           TEST"
 "x334         TEST"
 "x200         TEST"
) do (
  echo(
  echo ~~~~~~~~~~~~~~~~~~~~
  echo %%A
  set Mark=%%~A
  call :initStrLen%%Mark:~0,9%% StrLen
  echo Functional test 0 ... 8189 + 8191 + presets + x%times_test%
  call :func_test
  echo(done
  for /l %%l in (1 1 7) do call :test str%%l
)
set "StrLen="
 rem End Test Old

call :initStrLen1    StrLen1
call :initStrLen2    StrLen2
call :initStrLen2o   StrLen2o
call :initStrLen2i   StrLen2i
call :initStrLen912  StrLen912
call :initStrLen912o StrLen912o
call :initStrLen912i StrLen912i
:call :initStrLen821  StrLen821
call :initStrLen821o StrLen821o
call :initStrLenx334 StrLenx334
:call :initStrLen513  StrLen513
call :initStrLen513o StrLen513o
call :initStrLenx200 StrLenx200

::::::: rem var HeaderInfo is required to create the table header automatically
::::::: and if Macro loaded
:::::::::::::
::: oh no not so much otherwise the monitor on the right side will break
set "HeaderInfo=final1 2o 2i final1 x334 x200 912i 912o 821o 513o final2 " 
:set "HeaderInfo=513o 513o 912o 912o final2 final2" 
:set "HeaderInfo=final2 2o 912o 513o 912o 2o final2" 

set /a times=times_test*16
set /a times_random=20
for /f %%0 in ("!! '") do (
  if %%0 GTR ' setlocal enabledelayedexpansion
  for /l %%N in (1 1 7) do call :testx str%%N len %HeaderInfo%
  for /l %%N in (1 1 %times_random%) do (
    echo Random %%N/%times_random%
    for /f %%N in ('set /a "!random! %%8187"') do set ^"strX=^
!str1:~,%%~N!^"
    call :testx strX len %HeaderInfo%
  )
  if %%0 lss ' endlocal
)
pause
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:testx
:::::::param:   strVar Dummy(writeLen) HeaderInfo
set /a columns=4
::HeaderInfo=1stheadColumn X Y n  
 %= buildHeader =%
set "line="
set "lineX="
::::::: Column two, the first column with the time output, 
::::::: can be safely ignored—it's always too high, 
::::::: no matter which macro is run first. 
::::::: The second time column with the same macro will output a correct value.
:::::::::::::::
:::::::: rem HeaderInfo is required to create the table header automatically
for /l %%l in (1 1 3) do for %%h in (x%times% %HeaderInfo% 0) do (
  if "!lineX!" equ "" if %%l equ 1 if %%h neq 0 (set "line=!line!+--------"
  ) else set "linex=!line!+"&echo !linex!
  if %%l equ 2 if %%h neq 0 (
    set "name=%%~h "
    for /l %%L in (1 1 4) do if "!name:~8,1!" equ "" set "name= !name! "
    <nul set/p "=I!name:~0,8!"
  ) else echo I
  if %%l equ 3 if %%h equ 0 echo !linex!
)
set /a i=0
:beginloop
call :loop %*
set /a i+=1
if !i! lss !columns! goto :beginloop
echo !linex!
echo(
goto :eof
:loop
set /a N=1
:versions
:::::::::::::::::::::::::::
:: rem Pro[ver] [times] [stringVar]
call :pro%2 %times% %1
if !N! equ 1 <nul (
 set/p "=I  !len!	 "
) else (
 %timediff% t1 t2 diff
 <nul set/p.="I !diff:~6!  "
)
set /a N+=1
if "%3" equ "" (
  echo I
  goto :eof
)
shift /1
goto :versions
goto :eof
:Pro = [times] [stringVar]
:pro513
set t1=!time!
for /l %%i in (1 1 %1) do %strLen513% %2 len
set t2=!time!
goto :eof
:pro513o
set t1=!time!
for /l %%i in (1 1 %1) do %strLen513o% %2 len
set t2=!time!
goto :eof
:prox200
set t1=!time!
for /l %%i in (1 1 %1) do %strLenx200% %2 len
set t2=!time!
goto :eof
:pro821
set t1=!time!
for /l %%i in (1 1 %1) do %strLen821% %2 len
set t2=!time!
goto :eof
:pro821o
set t1=!time!
for /l %%i in (1 1 %1) do %strLen821o% %2 len
set t2=!time!
goto:eof
:prox334
set t1=!time!
for /l %%i in (1 1 %1) do %strLenx334% %2 len
set t2=!time!
goto:eof
:pro912
set t1=!time!
for /l %%i in (1 1 %1) do %strLen912% %2 len
set t2=!time!
goto :eof
:pro912o
set t1=!time!
for /l %%i in (1 1 %1) do %strLen912o% %2 len
set t2=!time!
goto :eof
:pro912i
set t1=!time!
for /l %%i in (1 1 %1) do %strLen912i% %2 len
set t2=!time!
goto :eof
:proFinal1
set t1=!time!
for /l %%i in (1 1 %1) do %strLen1% %2 len
set t2=!time!
goto :eof
:proFinal2
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2% %2 len
set t2=!time!
goto :eof
:pro2o
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2o% %2 len
set t2=!time!
goto :eof
:pro2i
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2i% %2 len
set t2=!time!
goto :eof
:prolen
set t1=!time!
for /l %%i in (1 1 2) do %strLen2o% %2 len
set t2=!time!

goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:test
setlocal EnableDelayedExpansion
set len=
for /l %%I in (1 1 1) do (
  set t1=!time!
  for /l %%I in (1 1 %times_test%) do %strLen% %1 len
  set t2=!time!
  %timediff% t1 t2 diff
  <nul set /p =!diff:~6!  
)
echo Check: len=!len!
endlocal
goto :eof

:::::::::::::::::::::::::::::::::::::::::::::::::
:func_test
setlocal EnableDelayedExpansion
set /a NN=1
:againf_t
set t1=!time!
set "A="
for /L %%L in (0,1,8189) do (
  %strLen% A len
set A=^
!A!X
  title in %%L out !len!
  if !len! neq %%L echo  in %%L out !len!&pause
)
 %strLen% str1 len
  title in 8191 out !len!
  if !len! neq 8191 echo  in 8191 out !len!

set t2=!time!
%timediff% t1 t2 diff
echo !diff:~6!
if !NN! equ %times_func% goto :eof
set /a nn+=1
goto :againf_t

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen1 Final
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f "tokens=2" %%? in ("%%!%%! D E") do for %%. in (1 2) do if %%.==2 (^
  for /f "tokens=1,2" %%1 in ("%%!$args%%!") do (^
    set "$L=0"^&^
    (if defined %%~1^
      (if "" neq "%%!%%~1:~255%%!"^
        (if "" neq "%%!%%~1:~4095%%!"^
          (set "$=%%!%%~1:~4096%%!"^&set "$L=4096") else set "$=%%!%%~1%%!"^
        )^&^
        (if defined $^
          set ^"$scale=^
%%!$:~255,1%%!%%!$:~511,1%%!%%!$:~767,1%%!%%!$:~1023,1%%!%%!$:~1279,1%%!^
%%!$:~1535,1%%!%%!$:~1791,1%%!%%!$:~2047,1%%!%%!$:~2303,1%%!%%!$:~2559,1%%!^
%%!$:~2815,1%%!%%!$:~3071,1%%!%%!$:~3327,1%%!%%!$:~3583,1%%!%%!$:~3839,1%%!^
FEDCBA9876543210^"^&^
          set /a "$L+=0x%%!$scale:~15,1%%!*256"^
        )^
      )^&^
      for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
333333333333333322222222222222221111111111111111^"^&^
      set /a "$L+=0x%%!$:~511,1%%!%%!$:~255,1%%!"^
    )^&^
    for %%# in (%%!$L%%!) do (if %%?==D endlocal)^&set "%%~2=%%#"^
  )^
) else (if %%?==D setlocal EnableDelayedExpansion)^& set $args=
goto :eof


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
               FOR %%H IN (FEDCBA9876543210) DO FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
%==% for /f "tokens=2" %%? in ("%%!%%! D E") do for %%. in (1 2) do if %%.==2 (^
%=  =% for /f "tokens=1,2" %%1 in ("%%!$args%%!") do for %%3 in (%%~1) do (^
%=    =% if defined %%3 (^
%=      =% (^
%=        =% if "" neq "%%!%%3:~255%%!" (^
%=          =% if "" neq "%%!%%3:~4095%%!" (^
%=            =% set "$=%%!%%3:~4096%%!"^
%=          =% ) else set "$=%%!%%3%%!"^
%=        =% ) ^& (^
%=          =% if defined $ (^
%=            =% set ^"$Scale=^
%=             =%%%!$:~255,1%%!%%!$:~511,1%%!%%!$:~767,1%%!%%!$:~1023,1%%!^
%=             =%%%!$:~1279,1%%!%%!$:~1535,1%%!%%!$:~1791,1%%!%%!$:~2047,1%%!^
%=             =%%%!$:~2303,1%%!%%!$:~2559,1%%!%%!$:~2815,1%%!%%!$:~3071,1%%!^
%=             =%%%!$:~3327,1%%!%%!$:~3583,1%%!%%!$:~3839,1%%!%%H^"^&^
%=            =% if "" neq "%%!%%3:~4095%%!" (^
%=              =% set /a "$L=0x%%!$Scale:~15,1%%!*256+4096"^
%=            =% ) else set /a "$L=0x%%!$Scale:~15,1%%!*256"^
%=          =% ) else if "" neq "%%!%%3:~4095%%!" set "$L=4096"^
%=        =% ) else set "$L=0"^
%=      =% )^&^
%=      =% for %%# in (%%!$L%%!) do set ^"$=%%!%%3:~%%#%%!^
%=       =%%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H^
%=       =%FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
%=       =%BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
%=       =%7777777777777777666666666666666655555555555555554444444444444444^
%=       =%333333333333333322222222222222221111111111111111^"^&^
%=      =% for %%# in ("%%!$L%%!+0x%%!$:~511,1%%!%%!$:~255,1%%!") do (^
%=        =% (if %%?==D endlocal)^&set /A "%%~2=%%#"^
%=      =% )^
%=    =% ) else (if %%?==D endlocal)^&set "%%~2=0"^
%=  =% )^
%==% ) else (if %%?==D setlocal EnableDelayedExpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2o Final2o 2 readable
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do for %%3 in (%%~1) do if defined %%3 (^
  (if "" neq "%%!%%3:~4095%%!" (set "$=%%!%%3:~4096%%!") else set "$=%%!%%3%%!")^
  ^&^ (if defined $ (^
    set ^"$Scale=^
%%!$:~255,1%%!%%!$:~511,1%%!%%!$:~767,1%%!%%!$:~1023,1%%!%%!$:~1279,1%%!^
%%!$:~1535,1%%!%%!$:~1791,1%%!%%!$:~2047,1%%!%%!$:~2303,1%%!%%!$:~2559,1%%!^
%%!$:~2815,1%%!%%!$:~3071,1%%!%%!$:~3327,1%%!%%!$:~3583,1%%!%%!$:~3839,1%%!^
FEDCBA9876543210^"^&^
    if "" neq "%%!%%3:~4095%%!" (^
     set /a "$L=0x%%!$Scale:~15,1%%!00+4096"^
    ) else set /a "$L=0x%%!$Scale:~15,1%%!00"^
   ) else if "" neq "%%!%%3:~4095%%!" set "$L=4096"^
  ) ^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%3:~%%#%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
333333333333333322222222222222221111111111111111^"^&^
  for %%# in ("%%#+0x%%!$:~511,1%%!%%!$:~255,1%%!") do (if %%? lss ' endlocal)^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal)^&set "%%~2=0"^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2i Final2o 2 readable
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do if defined %%~1 (^
  (if "%%!%%~1:~4095,1%%!" equ "" (set "$L="^&set "$=A%%!%%1%%!"^
   ) else set "$L=1"^&set "$=A%%!%%1:~4096%%!"^
  )^& set ^"$Scale=^
%%!$:~256,1%%!%%!$:~512,1%%!%%!$:~768,1%%!%%!$:~1024,1%%!%%!$:~1280,1%%!^
%%!$:~1536,1%%!%%!$:~1792,1%%!%%!$:~2048,1%%!%%!$:~2304,1%%!%%!$:~2560,1%%!^
%%!$:~2816,1%%!%%!$:~3072,1%%!%%!$:~3328,1%%!%%!$:~3584,1%%!%%!$:~3840,1%%!^
FEDCBA9876543210^"^&^
  set /a "$L=0x%%!$L%%!%%!$Scale:~15,1%%!00"^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%1:~%%#%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
333333333333333322222222222222221111111111111111^"^&^
  for %%# in ("%%#+0x%%!$:~511,1%%!%%!$:~255,1%%!") do (if %%? lss ' endlocal)^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal)^&set "%%~2=0"^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen912
 %= rem HeaderMakeMakro =%   FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do ^
 %= MainMakro =%if defined %%~1 (^
  (if "" neq "%%!%%~1:~911,1%%!" (^
    set $scale=%%!%%~1:~911,1%%!%%!%%~1:~1823,1%%!%%!%%~1:~2735,1%%!%%!%%~1:~3647,1%%!%%!%%~1:~4559,1%%!%%!%%~1:~5471,1%%!%%!%%~1:~6383,1%%!%%!%%~1:~7295,1%%!876543210^&^
    set /a "$L=!$scale:~8,1!*912"^
   ) else set /a "$L=0"^
  )^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210^
11000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111          ^
99999999999988888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888887777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666655555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555554444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333322222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111^"^&^
  for %%# in ("%%!$L%%!+%%!$:~2735,1%%!%%!$:~1823,1%%!%%!$:~911,1%%!") do (if %%? lss ' endlocal) ^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal) ^&set "%%~2=0"^
 %= rem FooterMakeMakro =%^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen912i
 %= rem HeaderMakeMakro =%   FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do ^
 %= MainMakro =%if defined %%~1 (^
  set $scale=%%!%%~1:~911,1%%!%%!%%~1:~1823,1%%!%%!%%~1:~2735,1%%!%%!%%~1:~3647,1%%!%%!%%~1:~4559,1%%!%%!%%~1:~5471,1%%!%%!%%~1:~6383,1%%!%%!%%~1:~7295,1%%!876543210^&^
  set /a "$L=0x!$scale:~8,1!*912"^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210^
11000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111          ^
99999999999988888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888887777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666655555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555554444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333322222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111^"^&^
  for %%# in ("%%#+%%!$:~2735,1%%!%%!$:~1823,1%%!%%!$:~911,1%%!") do (if %%? lss ' endlocal)^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal) ^&set "%%~2=0"^
 %= rem FooterMakeMakro =%^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen912o
 %= rem HeaderMakeMakro =%   FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do ^
 %= MainMakro =%if defined %%~1 (^
  set $scale=%%!%%~1:~911,1%%!%%!%%~1:~1823,1%%!%%!%%~1:~2735,1%%!%%!%%~1:~3647,1%%!%%!%%~1:~4559,1%%!%%!%%~1:~5471,1%%!%%!%%~1:~6383,1%%!%%!%%~1:~7295,1%%!876543210^&^
  set /a "$L=!$scale:~8,1!*912"^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210^
11000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111          ^
99999999999988888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888887777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666655555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555554444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333322222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111^"^&^
  for %%# in ("%%#+%%!$:~2735,1%%!%%!$:~1823,1%%!%%!$:~911,1%%!") do (if %%? lss ' endlocal)^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal) ^&set "%%~2=0"^
 %= rem FooterMakeMakro =%^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen821
 %= rem HeaderMakeMakro =%   FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do ^
  %= MainMakro =%if defined %%~1 (^
  (if "" neq "%%!%%~1:~820,1%%!" (^
    set "$scale=%%!%%~1:~820,1%%!%%!%%~1:~1641,1%%!%%!%%~1:~2462,1%%!%%!%%~1:~3283,1%%!%%!%%~1:~4104,1%%!%%!%%~1:~4925,1%%!%%!%%~1:~5746,1%%!%%!%%~1:~6567,1%%!%%!%%~1:~7388,1%%!9876543210"^&^
    set /a "$L=0x!$scale:~9,1!*821"^
   ) else set /a "$L=0"^
  )^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
88888888888888888888877777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777776666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555544444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444443333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222211111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111110000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000^
21111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000^
09876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210^"^&^
  for %%# in ("%%!$L%%!-1000+1%%!$:~820,1%%!%%!$:~1641,1%%!%%!$:~2462,1%%!") do (if %%? lss ' endlocal) ^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal) ^&set "%%~2=0"^
 %= rem FooterMakeMakro =%^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen821o
 %= rem HeaderMakeMakro =%   FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do ^
 %= MainMakro =%if defined %%~1 (^
  set "$scale=%%!%%~1:~820,1%%!%%!%%~1:~1641,1%%!%%!%%~1:~2462,1%%!%%!%%~1:~3283,1%%!%%!%%~1:~4104,1%%!%%!%%~1:~4925,1%%!%%!%%~1:~5746,1%%!%%!%%~1:~6567,1%%!%%!%%~1:~7388,1%%!9876543210"^&^
  set /a "$L=0x!$scale:~9,1!*821"^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
09876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210^
2111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111          ^
8888888888888888888887777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777777666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666655555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555554444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333322222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111^"^&^
  for %%# in ("%%!$L%%!+%%!$:~2462,1%%!%%!$:~1641,1%%!%%!$:~820,1%%!") do (if %%? lss ' endlocal) ^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal) ^&set "%%~2=0"^
 %= rem FooterMakeMakro =%^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLenx334
 %= rem HeaderMakeMakro =%   FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do ^
 %= MainMakro =%if defined %%~1 (^
  set "$scale=%%!%%~1:~820,1%%!%%!%%~1:~1641,1%%!%%!%%~1:~2462,1%%!%%!%%~1:~3283,1%%!%%!%%~1:~4104,1%%!%%!%%~1:~4925,1%%!%%!%%~1:~5746,1%%!%%!%%~1:~6567,1%%!%%!%%~1:~7388,1%%!9876543210"^&^
  set /a "$L=0x!$scale:~9,1!*821"^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
43210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
33333222222222222222211111111111111110000000000000000FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA9999999999999999888888888888888877777777777777776666666666666666555555555555555544444444444444443333333333333333222222222222222211111111111111110000000000000000FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA9999999999999999888888888888888877777777777777776666666666666666555555555555555544444444444444443333333333333333222222222222222211111111111111110000000000000000FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA9999999999999999888888888888888877777777777777776666666666666666555555555555555544444444444444443333333333333333222222222222222211111111111111110000000000000000^
3333333333333333333333333333333333333333333333333333322222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111^"^&^
  for %%# in ("%%#+0x%%!$:~2462,1%%!%%!$:~1641,1%%!%%!$:~820,1%%!") do (if %%? lss ' endlocal) ^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal) ^&set "%%~2=0"^
 %= rem FooterMakeMakro =%^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen513
 %= rem HeaderMakeMakro =%   FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do ^
 %= MainMakro =%if defined %%~1 (^
  (if "" neq "%%!%%~1:~512,1%%!" (^
    set "$scale=%%!%%~1:~512,1%%!%%!%%~1:~1025,1%%!%%!%%~1:~1538,1%%!%%!%%~1:~2051,1%%!%%!%%~1:~2564,1%%!%%!%%~1:~3077,1%%!%%!%%~1:~3590,1%%!%%!%%~1:~4103,1%%!%%!%%~1:~4616,1%%!%%!%%~1:~5129,1%%!%%!%%~1:~5642,1%%!%%!%%~1:~6155,1%%!%%!%%~1:~6668,1%%!%%!%%~1:~7181,1%%!%%!%%~1:~7694,1%%!FEDCBA9876543210"^&^
    set /a "$L=0x!$scale:~15,1!*513"^
   ) else set /a "$L=0"^
  )^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210^
11100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111          ^
55555555555554444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333322222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111^"^&^
  for %%# in ("%%!$L%%!+%%!$:~1538,1%%!%%!$:~1025,1%%!%%!$:~512,1%%!") do (if %%? lss ' endlocal) ^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal) ^&set "%%~2=0"^
 %= rem FooterMakeMakro =%^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen513o
 %= rem HeaderMakeMakro =%   FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do ^
 %= MainMakro =%if defined %%~1 (^
  set "$scale=%%!%%~1:~512,1%%!%%!%%~1:~1025,1%%!%%!%%~1:~1538,1%%!%%!%%~1:~2051,1%%!%%!%%~1:~2564,1%%!%%!%%~1:~3077,1%%!%%!%%~1:~3590,1%%!%%!%%~1:~4103,1%%!%%!%%~1:~4616,1%%!%%!%%~1:~5129,1%%!%%!%%~1:~5642,1%%!%%!%%~1:~6155,1%%!%%!%%~1:~6668,1%%!%%!%%~1:~7181,1%%!%%!%%~1:~7694,1%%!FEDCBA9876543210"^&^
  set /a "$L=0x!$scale:~15,1!*513"^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210987654321098765432109876543210^
11100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111000000000099999999998888888888777777777766666666665555555555444444444433333333332222222222111111111100000000009999999999888888888877777777776666666666555555555544444444443333333333222222222211111111110000000000999999999988888888887777777777666666666655555555554444444444333333333322222222221111111111          ^
55555555555554444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333322222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222221111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111^"^&^
  for %%# in ("%%!$L%%!+%%!$:~1538,1%%!%%!$:~1025,1%%!%%!$:~512,1%%!") do (if %%? lss ' endlocal) ^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal) ^&set "%%~2=0"^
 %= rem FooterMakeMakro =%^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLenx200
 %= rem HeaderMakeMakro =%   FOR /F %%! IN ("! ^! ^^^!") DO ^
set %~1=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do ^
 %= MainMakro =%if defined %%~1 (^
  set "$scale=%%!%%~1:~512,1%%!%%!%%~1:~1025,1%%!%%!%%~1:~1538,1%%!%%!%%~1:~2051,1%%!%%!%%~1:~2564,1%%!%%!%%~1:~3077,1%%!%%!%%~1:~3590,1%%!%%!%%~1:~4103,1%%!%%!%%~1:~4616,1%%!%%!%%~1:~5129,1%%!%%!%%~1:~5642,1%%!%%!%%~1:~6155,1%%!%%!%%~1:~6668,1%%!%%!%%~1:~7181,1%%!%%!%%~1:~7694,1%%!FEDCBA9876543210"^&^
  set /a "$L=0x!$scale:~15,1!*513"^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%~1:~%%#%%!^
0FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
0FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA9999999999999999888888888888888877777777777777776666666666666666555555555555555544444444444444443333333333333333222222222222222211111111111111110000000000000000FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCBBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA9999999999999999888888888888888877777777777777776666666666666666555555555555555544444444444444443333333333333333222222222222222211111111111111110000000000000000^
21111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111^"^&^
  for %%# in ("%%#+0x%%!$:~1538,1%%!%%!$:~1025,1%%!%%!$:~512,1%%!") do (if %%? lss ' endlocal) ^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal) ^&set "%%~2=0"^
 %= rem FooterMakeMakro =%^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initTimediff  
::: 32 characters shortened
for /f %%! in ("! ^! ^^^!") do ^
set timediff=for /f %%? in ("%%!%%! '") do for /l %%# in (1 1 2) do if %%# equ 2 (for /f "tokens=1-3" %%- in ("%%!_i_%%!") do set "_t1_=%%!%%~-: =0%%!"^&set "_t2_=%%!%%~.: =0%%!"^&set /a "_d_=(8640000+(((1%%!_t2_:~,2%%!*60+1%%!_t2_:~3,2%%!)*60+1%%!_t2_:~6,2%%!)*100+1%%!_t2_:~-2%%!-36610100)-(((1%%!_t1_:~,2%%!*60+1%%!_t1_:~3,2%%!)*60+1%%!_t1_:~6,2%%!)*100+1%%!_t1_:~-2%%!-36610100))%%8640000,_o_=100000000+(_d_%%100),_d_/=100,_o_+=(_d_%%60)*100,_d_/=60,_o_+=(_d_%%60)*10000+_d_/60*1000000"^&for %%' in ("%%!_o_:~1,2%%!:%%!_o_:~3,2%%!:%%!_o_:~5,2%%!.%%!_o_:~-2%%!") do (if %%? lss ' endlocal)^&if "%%~/"=="" (echo %%~') else set "%%~/=%%~'") else (if %%? GTR ' setlocal enabledelayedexpansion)^&set _i_=
goto :eof
the script

Code: Select all

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2i Final2i 
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set StrLen=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%!") do if defined %%~1 (^
  (if "%%!%%~1:~4095,1%%!" equ "" (set "$L="^&set "$=A%%!%%1%%!"^
   ) else set "$L=1"^&set "$=A%%!%%1:~4096%%!"^
  )^& set ^"$Scale=^
%%!$:~256,1%%!%%!$:~512,1%%!%%!$:~768,1%%!%%!$:~1024,1%%!%%!$:~1280,1%%!^
%%!$:~1536,1%%!%%!$:~1792,1%%!%%!$:~2048,1%%!%%!$:~2304,1%%!%%!$:~2560,1%%!^
%%!$:~2816,1%%!%%!$:~3072,1%%!%%!$:~3328,1%%!%%!$:~3584,1%%!%%!$:~3840,1%%!^
FEDCBA9876543210^"^&^
  set /a "$L=0x%%!$L%%!%%!$Scale:~15,1%%!00"^&^
  for %%# in (%%!$L%%!) do set ^"$=%%!%%1:~%%#%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
333333333333333322222222222222221111111111111111^"^&^
  for %%# in ("%%#+0x%%!$:~511,1%%!%%!$:~255,1%%!") do (if %%? lss ' endlocal)^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal)^&set "%%~2=0"^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

pieh-ejdsch
Posts: 257
Joined: 04 Mar 2014 11:14
Location: germany

Re: strLen boosted

#56 Post by pieh-ejdsch » 04 Aug 2025 08:25

I couldn't resist writing an even shorter and faster version than yesterday's after trying out lots of different things.
I noticed the following:
A for variable with a tilde ~ slows down execution because any quotation marks have to be removed first—regardless of whether there are any or not.
Using a for variable in exclamation marks instead of a hard-coded variable in exclamation marks will also slow down the code. The for variable is resolved first, followed by the variable name.

Hexadecimal numbers can be used in variables for extension – well, it's not documented, but so what.

I have not yet been able to determine with certainty to what extent hexadecimal numbers are resolved faster than decimal numbers. The variant 513o with x200 or 821o with x334 can be compared for this purpose. In the hexadecimal variant, 256 zeros can be removed in the first of three digits, while in the decimal variant only 100 zeros can be removed.

Code: Select all

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set StrLen=^
for /f %%? in ("%%!%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%! len") do if defined %%~1 (^
  (if "%%!%%~1:~4095,1%%!" equ "" (set "$L=0"^&set "$=A%%!%%1%%!"^
   ) else set "$L=1"^&set "$=A%%!%%1:~4096%%!"^
  )^& set ^"$Scale=^
%%!$:~256,1%%!%%!$:~512,1%%!%%!$:~768,1%%!%%!$:~1024,1%%!%%!$:~1280,1%%!^
%%!$:~1536,1%%!%%!$:~1792,1%%!%%!$:~2048,1%%!%%!$:~2304,1%%!%%!$:~2560,1%%!^
%%!$:~2816,1%%!%%!$:~3072,1%%!%%!$:~3328,1%%!%%!$:~3584,1%%!%%!$:~3840,1%%!^
FEDCBA9876543210^"^&^
  for %%# in (%%!$Scale:~15^^^,1%%!) do set ^"$=%%!$:~0x%%#00%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^"^&^
  for %%# in (0x%%!$L%%!%%#%%!$:~512^^^,1%%!%%!$:~256^^^,1%%!) do (^
  if %%? lss ' endlocal)^&set /A "%%~2=%%#"^
 ) else (if %%? lss ' endlocal)^&set "%%~2=0"^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof


The variant that should also work on the CMD line is: i.e. not in batch mode.
setlocal does not work there, of course, but the macro can be executed in “cmd/v”.

The upper version -^ also works in the CMD line, but the macro must be created in cmd/v:off.

Code: Select all

@echo off
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLenCMDline
:: Computes the number of bytes in a string.
:: %strLen% str len
::   str - [ByRef In] Name of the variable containing the string to be measured.
::   len - [ByRef Out] Name of the variable that receives the measured length.
:: Strings of up to 8191 characters are supported.
                                                FOR /F %%! IN ("! ^! ^^^!") DO ^
set StrLen=^
@for /f %%? in ("%%!%%! '") do @for %%. in (1 2) do @if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%! len") do @if defined %%~1 (^
  (if "%%!%%~1:~4095,1%%!" equ "" (set "$L=0"^&set "$=A%%!%%1%%!"^
   ) else set "$L=1"^&set "$=A%%!%%1:~4096%%!"^
  )^& set ^"$Scale=^
%%!$:~256,1%%!%%!$:~512,1%%!%%!$:~768,1%%!%%!$:~1024,1%%!%%!$:~1280,1%%!^
%%!$:~1536,1%%!%%!$:~1792,1%%!%%!$:~2048,1%%!%%!$:~2304,1%%!%%!$:~2560,1%%!^
%%!$:~2816,1%%!%%!$:~3072,1%%!%%!$:~3328,1%%!%%!$:~3584,1%%!%%!$:~3840,1%%!^
FEDCBA9876543210^"^&^
  for %%# in ("%%!$Scale:~15,1%%!") do @set ^"$=%%!$:~0x%%~#00%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^"^&^
  for %%# in ("0x%%!$L%%!%%~#%%!$:~512,1%%!%%!$:~256,1%%!") do @(^
  if %%? lss ' endlocal)^&set /A "%%~2=%%~#"^
 ) else (if %%? lss ' endlocal)^&set /a "%%~2=0"^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

aGerman
Expert
Posts: 4743
Joined: 22 Jan 2010 18:01
Location: Germany

Re: strLen boosted

#57 Post by aGerman » 04 Aug 2025 11:41

At first glance this seems to be faster for strings >= 256 characters and slower if for strings is < 256 characters. I have to dig deeper when I have a little more time. Especial because I don't get why %%? must be > ' for SETLOCAL and < ' for ENDLOCAL. At the moment that doesn't make any sense to me yet :lol:

Steffen

pieh-ejdsch
Posts: 257
Joined: 04 Mar 2014 11:14
Location: germany

Re: strLen boosted

#58 Post by pieh-ejdsch » 04 Aug 2025 15:39

The first token in the For-loop can actually be a single exclamation mark, just like in if.
The parser first evaluates the loop or the if and the exclamation mark is only resolved at execution time.
Two exclamation marks are also larger than the ' . Twice (empty) is also smaller than ' .

The exclamation mark is greater than the ' and nothing(empty) is less than the ' .

Since the command

Code: Select all

if ! GTR ' setlocal
is true if the delay is switched OFF and

Code: Select all

if ! lss ' endlocal
is true if the delay is switched ON - it is switched accordingly.
The ! in the first token becomes (empty) in the second if.
So if the delay is already switched OFF beforehand into the for - the second if results in a false.
Since the ' cannot be greater or less than itself - every if is a false.
Last edited by pieh-ejdsch on 05 Aug 2025 04:26, edited 1 time in total.

miskox
Posts: 668
Joined: 28 Jun 2010 03:46

Re: strLen boosted

#59 Post by miskox » 04 Aug 2025 22:22

This Compo's solution might help determing if DELAYEDEXPANSION is ON or OFF:

https://stackoverflow.com/questions/761 ... -is-active

Code: Select all

IF "!!" == "" (
  ECHO Delayed expansion is ON
)  ELSE (
  ECHO Delayed expansion is OFF
)
Saso

aGerman
Expert
Posts: 4743
Joined: 22 Jan 2010 18:01
Location: Germany

Re: strLen boosted

#60 Post by aGerman » 05 Aug 2025 11:11

@pieh-ejdsch
Thanks, got it now. I didn't consider that both expansion steps are performed, %%? to !! and !! to an empty string. And I would've expected it throws a syntax error due to a missing comparison operand in this case. (I know, reading is fun, it's all already explained over there https://stackoverflow.com/questions/409 ... se-scripts :lol:.)
Now I still have to figure out why it performs slower with short strings in my tests.

@miskox
Oh yes, relying on !! being expanded to an empty string if delayed expansion is enabled is exactly what we are doing in the macro code.

Steffen

Post Reply