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

#61 Post by einstein1969 » 06 Aug 2025 05:30

aGerman wrote:
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.
Yes, you're right, but I assumed there were no quotes for the variable. It seemed unnecessary to me, but they can be handled to avoid errors. So %%~1 is better.

I hadn't noticed the reduction with "FOR %%H IN (FEDCBA9876543210)" I had also tried but then I went back, I don't remember maybe to make it faster.

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

Re: strLen boosted

#62 Post by einstein1969 » 06 Aug 2025 06:49

In the meantime, to understand what pieh-ejdsch did (by the way, you did a great job!), I tested the functions.

I'm attaching the code for testing.

pieh-ejdsch, can you list the tricks you used and their contribution to speed?

I optimized for the lower part of the length because it's more likely to be used. I think you have an extra "set" for short strings. Perhaps yours can be optimized a little further.

Code: Select all

+--------+-------------+-------------+-------------+-------------+
I  len   I  final      I  final2     I  post #51   I  post #56   I
+--------+-------------+-------------+-------------+-------------+
I  8191  I  11.23      I  09.43      I  09.29      I  07.83      I
I  8191  I  11.23      I  09.33      I  09.34      I  07.83      I
I  8191  I  11.18      I  09.30      I  09.36      I  07.86      I
I  8191  I  11.21      I  09.31      I  09.27      I  07.86      I
+--------+-------------+-------------+-------------+-------------+

+--------+-------------+-------------+-------------+-------------+
I  len   I  final      I  final2     I  post #51   I  post #56   I
+--------+-------------+-------------+-------------+-------------+
I  6000  I  10.39      I  08.59      I  08.77      I  07.35      I
I  6000  I  10.48      I  08.63      I  08.57      I  07.40      I
I  6000  I  10.47      I  08.59      I  08.61      I  07.27      I
I  6000  I  10.40      I  08.63      I  08.70      I  07.34      I
+--------+-------------+-------------+-------------+-------------+

+--------+-------------+-------------+-------------+-------------+
I  len   I  final      I  final2     I  post #51   I  post #56   I
+--------+-------------+-------------+-------------+-------------+
I  4500  I  10.04      I  07.99      I  07.99      I  06.87      I
I  4500  I  10.00      I  08.06      I  09.30      I  07.30      I
I  4500  I  10.69      I  08.51      I  08.34      I  06.99      I
I  4500  I  10.24      I  08.26      I  08.25      I  07.06      I
+--------+-------------+-------------+-------------+-------------+

+--------+-------------+-------------+-------------+-------------+
I  len   I  final      I  final2     I  post #51   I  post #56   I
+--------+-------------+-------------+-------------+-------------+
I  2000  I  09.69      I  08.48      I  08.46      I  07.30      I
I  2000  I  09.71      I  08.49      I  08.45      I  07.33      I
I  2000  I  09.77      I  08.43      I  08.55      I  07.39      I
I  2000  I  09.65      I  08.41      I  08.41      I  07.38      I
+--------+-------------+-------------+-------------+-------------+

+--------+-------------+-------------+-------------+-------------+
I  len   I  final      I  final2     I  post #51   I  post #56   I
+--------+-------------+-------------+-------------+-------------+
I  1000  I  09.49      I  08.07      I  08.29      I  07.10      I
I  1000  I  09.35      I  08.13      I  08.09      I  07.21      I
I  1000  I  09.45      I  08.15      I  08.23      I  07.15      I
I  1000  I  09.37      I  08.09      I  08.02      I  07.27      I
+--------+-------------+-------------+-------------+-------------+

+--------+-------------+-------------+-------------+-------------+
I  len   I  final      I  final2     I  post #51   I  post #56   I
+--------+-------------+-------------+-------------+-------------+
I  200   I  06.59      I  06.01      I  05.91      I  06.89      I
I  200   I  06.53      I  06.02      I  05.88      I  06.78      I
I  200   I  06.50      I  05.89      I  05.90      I  06.78      I
I  200   I  06.53      I  05.89      I  05.87      I  06.79      I
+--------+-------------+-------------+-------------+-------------+

+--------+-------------+-------------+-------------+-------------+
I  len   I  final      I  final2     I  post #51   I  post #56   I
+--------+-------------+-------------+-------------+-------------+
I  10    I  06.38      I  05.85      I  05.91      I  06.73      I
I  10    I  06.34      I  05.79      I  05.79      I  06.72      I
I  10    I  06.31      I  05.81      I  05.80      I  06.72      I
I  10    I  06.32      I  05.79      I  05.79      I  06.73      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

:: 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%"
:: 100
set "str7=%str1:~,100%"
:: 10
set "str8=%str1:~,10%"

call :initTimediff

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


call :initStrLenFinal
call :initStrLenFinal2
call :initStrLen#51
call :initStrLen#56


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


rem call :test-funz

set loop=2000

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

pause

goto :eof


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen#56
:: 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#56=^
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

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen#51
:: 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#51=^
%==% 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


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
: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  post #51   I  post #56   I
echo +--------+-------------+-------------+-------------+-------------+

setlocal EnableDelayedExpansion

set i=0
for /L %%L in (1,1,1000000) do rem
:loop
	set len=

	%strLen% %1 len
	set/p.="I  !len!	 I  "<nul

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

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

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

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


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

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


endlocal
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

:test-funz

	setlocal EnableDelayedExpansion


	echo(
	echo Functional test
	echo(

	call :sub-funz final

	call :sub-funz "final 2"

	call :sub-funz "#51"

	call :sub-funz "#56"


goto :eof


:sub-funz

	set "funct=%~1"

	set /p ".=!funct! :"<nul

	set "str="
	for /L %%L in (0,1,8185) do (
		set len=
		if "%funct%" equ "final" 	%strLen% str len
		if "%funct%" equ "final 2" 	%strLen2% str len
		if "%funct%" equ "#51" 		%strLen#51% str len
		if "%funct%" equ "#56" 		%strLen#56% str len
		set "str=!str!X"
		title "%%L" "!len!"
		if "!len!" neq "%%L" echo error & pause
	)
	echo OK.

	echo(

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

ps, I added the post number to better recognize them
EDIT :update code

Francesco
Last edited by einstein1969 on 06 Aug 2025 10:30, edited 1 time in total.

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

Re: strLen boosted

#63 Post by aGerman » 06 Aug 2025 10:05

but I assumed there were no quotes for the variable
That's a fair assumption. We can just remark it in the macro description as this is our contract with the user :wink:
I hadn't noticed the reduction with "FOR %%H IN (FEDCBA9876543210)"
Everything that comes before the "set StrLen=..." will not become part of the macro code. In other words, %%H is already expanded during the initialization of the macro. I tried to visualize this using all-caps style and the right alignment at the 80th column. So, all that %%H does is shortening the macro code in the batch file (not the resulting code saved in the StrLen variable). It doesn't have any impact on the performance of the macro.
I tested the functions
Your tests also confirm that pieh-ejdsch's code is slower for strings < 256 characters. That's unfortunate because the probability that we find those strings in real world is far higher than having strings with thousands of characters :( I still didn't have enough time to investigate for what reason though.
I added the post number to better recognize them
Way better, thanks. I tried to give them names which has been insufficient and misleading.

Steffen

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

Re: strLen boosted

#64 Post by einstein1969 » 06 Aug 2025 10:38

I read the code of pieh-ejdsch and everything has been optimized to perform fewer sets and normalized to be more streamlined.

Even operations have been cleverly wrapped with 0x, 0x100 prefixes, etc.

But it performs the same number of sets regardless of the string length. One or two sets should be eliminated for shorter strings, which is what I did to maximize speed.

so a fusion of the techniques, if possible, could lower the times

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

Re: strLen boosted

#65 Post by pieh-ejdsch » 07 Aug 2025 09:00

Well, Francesco, I tinkered with the macros until they got faster and achieved this performance

The quotation marks can be omitted everywhere if the variable expansion does not contain a comma.
The closing brackets are attached directly to the variables to be set, as is the follow-up command.
set /a statements are probably a little slower than direct variable creation.
I've been using the if with a single exclamation mark for a while now, and this means that the comparison can also be done without quotation marks.
Yes, and this also makes calculations and variable expansion with hexadecimal numbers easier.

And I've made the batch/CMD version a little easier.

If the macro is only to be processed in batch mode, the variable expansion with commas can simply be escaped (as can other characters that require this).

The latest version is now even faster.
If the quotation marks are removed, the macro runs.
However, this is only suitable for batch processing because escaping reacts differently in the CMD line.
So much for the speedup.

Code: Select all

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2e
:: 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.
      %= #=escape =%      FOR /F "tokens=1,2,4" %%! 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 %%! equ %%!%%1:~4095%%! (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
results

Code: Select all

Check length str1 gtr 8190 X

~~~~~~~~~~~~~~~~~~~~
"2f           TEST"
Functional test 0 ... 8189 + 8191 + presets + x400 with Delayedexpansion ON
06.66
06.30
Functional test 0 ... 8189 + 8191 + presets + x400 with Delayedexpansion OFF
06.35
06.39

~~~~~~~~~~~~~~~~~~~~
"2e           TEST"
Functional test 0 ... 8189 + 8191 + presets + x400 with Delayedexpansion ON
06.31
06.31
Functional test 0 ... 8189 + 8191 + presets + x400 with Delayedexpansion OFF
06.33
06.33

~~~~~~~~~~~~~~~~~~~~
"2f           TEST"
Functional test 0 ... 8189 + 8191 + presets + x400 with Delayedexpansion ON
06.36
06.36
Functional test 0 ... 8189 + 8191 + presets + x400 with Delayedexpansion OFF
06.36
06.39

~~~~~~~~~~~~~~~~~~~~
"2           Final"
Functional test 0 ... 8189 + 8191 + presets + x400 with Delayedexpansion ON
07.18
07.18
Functional test 0 ... 8189 + 8191 + presets + x400 with Delayedexpansion OFF
07.24
07.22

~~~~~~~~~~~~~~~~~~~~
"2i           TEST"
Functional test 0 ... 8189 + 8191 + presets + x400 with Delayedexpansion ON
07.28
07.32
Functional test 0 ... 8189 + 8191 + presets + x400 with Delayedexpansion OFF
07.28
07.30
done
+--------+--------+--------+--------+--------+--------+--------+
I  x2800 I final1 I   2e   I   2f   I   2i   I final2 I final1 I
+--------+--------+--------+--------+--------+--------+--------+
I  8191  I 01.53  I 00.77  I 00.82  I 00.89  I 01.01  I 01.17  I
+--------+--------+--------+--------+--------+--------+--------+
I  6000  I 01.54  I 00.78  I 00.86  I 00.89  I 01.02  I 01.17  I
+--------+--------+--------+--------+--------+--------+--------+
I  4500  I 01.55  I 00.78  I 00.85  I 00.89  I 01.03  I 01.17  I
+--------+--------+--------+--------+--------+--------+--------+
I  1000  I 01.54  I 00.77  I 00.84  I 00.91  I 01.03  I 01.17  I
+--------+--------+--------+--------+--------+--------+--------+
I  600   I 01.54  I 00.78  I 00.85  I 00.91  I 01.02  I 01.17  I
+--------+--------+--------+--------+--------+--------+--------+
I  200   I 01.53  I 00.78  I 00.85  I 00.90  I 01.01  I 01.17  I
+--------+--------+--------+--------+--------+--------+--------+
I  10    I 01.54  I 00.78  I 00.85  I 00.91  I 01.03  I 01.17  I
+--------+--------+--------+--------+--------+--------+--------+
I  5789  I 01.63  I 00.83  I 00.88  I 00.94  I 01.06  I 01.23  I
+--------+--------+--------+--------+--------+--------+--------+
I  6678  I 01.65  I 00.82  I 00.91  I 00.94  I 01.08  I 01.25  I
+--------+--------+--------+--------+--------+--------+--------+
I  4537  I 01.61  I 00.81  I 00.89  I 00.94  I 01.07  I 01.22  I
+--------+--------+--------+--------+--------+--------+--------+
I  1162  I 01.56  I 00.78  I 00.86  I 00.90  I 01.04  I 01.19  I
+--------+--------+--------+--------+--------+--------+--------+
I  7940  I 01.68  I 00.84  I 00.91  I 00.95  I 01.08  I 01.27  I
+--------+--------+--------+--------+--------+--------+--------+
I  5708  I 01.61  I 00.82  I 00.89  I 00.94  I 01.08  I 01.23  I
+--------+--------+--------+--------+--------+--------+--------+
I  7681  I 01.66  I 00.81  I 00.91  I 00.95  I 01.10  I 01.26  I
+--------+--------+--------+--------+--------+--------+--------+
I  6429  I 01.64  I 00.83  I 00.89  I 00.95  I 01.08  I 01.23  I
+--------+--------+--------+--------+--------+--------+--------+
I  73    I 01.55  I 00.79  I 00.84  I 00.91  I 01.04  I 01.19  I
+--------+--------+--------+--------+--------+--------+--------+
I  5045  I 01.63  I 00.81  I 00.90  I 00.99  I 01.07  I 01.24  I
+--------+--------+--------+--------+--------+--------+--------+
I  1894  I 01.58  I 00.79  I 00.86  I 00.90  I 01.04  I 01.22  I
+--------+--------+--------+--------+--------+--------+--------+
I  2162  I 01.58  I 00.80  I 00.86  I 00.92  I 01.06  I 01.21  I
+--------+--------+--------+--------+--------+--------+--------+
I  7965  I 01.67  I 00.83  I 00.91  I 00.95  I 01.09  I 01.25  I
+--------+--------+--------+--------+--------+--------+--------+
I  771   I 01.56  I 00.78  I 00.87  I 00.93  I 01.06  I 01.19  I
+--------+--------+--------+--------+--------+--------+--------+
I  7999  I 01.66  I 00.83  I 00.89  I 00.96  I 01.09  I 01.27  I
+--------+--------+--------+--------+--------+--------+--------+
I  5053  I 01.61  I 00.81  I 00.87  I 00.92  I 01.07  I 01.22  I
+--------+--------+--------+--------+--------+--------+--------+
I  6121  I 01.63  I 00.82  I 00.89  I 00.94  I 01.06  I 01.23  I
+--------+--------+--------+--------+--------+--------+--------+
I  3805  I 01.60  I 00.81  I 00.92  I 00.92  I 01.05  I 01.22  I
+--------+--------+--------+--------+--------+--------+--------+
I  1607  I 01.56  I 00.80  I 00.86  I 00.90  I 01.04  I 01.21  I
+--------+--------+--------+--------+--------+--------+--------+
I  5942  I 01.62  I 00.82  I 00.89  I 00.94  I 01.06  I 01.22  I
+--------+--------+--------+--------+--------+--------+--------+
Drücken Sie eine beliebige Taste . . .


[edit] testcript updated -->output for Daylayedexpansion ON/OFF [/edit]
[edit2]testscript updated -->+Versions 2x 2y 2z[/edit2]
[edit3]testscript updadet -->mod Version 2x + 2w [/edit]
[edit4]
Yes, I updated the test script again... you know, a new version.
Hopefully I won't run out of letters.
I don't know why I started with “i”! Actually,
I thought I would stop with “a”
but so many complicated processes came to mind that I had to play around on the keyboard.
And so I had to continue with “z”.
One would hope that operating systems would finally stop with the updates at “a”,
but they constantly come up with new nonsense, and that's why it continues at the back.
[/edit4]

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

: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:^=  %
set "x="
echo(
echo Check length str1 gtr 8190 %str1:~8190%
:: 6000
set "str2=%str1:~,6000%"
:: 4000
set "str3=%str1:~,4000%"
:: 2000
set "str4=%str1:~,2000%"
:: 1000
set "str5=%str1:~,1000%"
set "str510=%str1:~,510%
set "str511=%str1:~,511%
set "str512=%str1:~,512%
:: 200
set "str6=%str1:~,200%"
:: 10
set "str7=%str1:~,10%"
call :initTimediff

:: Test echo OFF =1  ON =[empty] 
for %%T in (   1    ) do set testecho=rem
goto :beginTestOld
 "2            Final"
 "2a           TEST"
 "2b           TEST"
 "2c           TEST"
 "2d           TEST"
 "2e           TEST"
 "2f           TEST"
 "2i           TEST"
 "2y           TEST"
 "2z           TEST"
 "All      Batch and CMDline"

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:BeginTestOld
set /a times_func=3
set /a times_test=1200
set skip1-7= rem
:goto :endTestOld
for %%A in (
 "2v           TEST"
 "2w           TEST"
 "2x           TEST"
 "2y           TEST"
 "All      Batch and CMDline"
) do (
  echo(
  echo ~~~~~~~~~~~~~~~~~~~~
  echo %%A
  set Mark=%%~A
  setlocal enabledelayedexpansion
  if ! gtr ' (echo Delayed OFF) else echo Delayed ON
  call :initStrLen%%Mark:~0,9%% StrLen
  %testecho% echo on
  %skip1-7%  call :test str1
  %skip1-7% call :test str2
  %skip1-7% call :test str3
  %skip1-7% call :test str4
  %skip1-7% call :test str5
  %skip1-7% call :test str6
  %skip1-7% call :test str7
  %skip1-7% call :test str510
  %skip1-7% call :test str511
  %skip1-7% call :test str512
  %skip1-7% call :test str0
  %testecho% pause
  %testecho% echo off
  echo Functional test 0 ... 8189 + 8191 with Delayedexpansion ON ^(create macro^)
  call :func_test
  endlocal
  if ! gtr ' (echo Delayed OFF) else echo Delayed ON
  call :initStrLen%%Mark:~0,9%% StrLen
  %testecho% echo on
  %skip1-7% call :test str1
  %testecho% pause
  %testecho% echo off
  %skip1-7% call :test str2
  %skip1-7% call :test str3
  %skip1-7% call :test str4
  %skip1-7% call :test str5
  %skip1-7% call :test str6
  %skip1-7% call :test str7
  %skip1-7% call :test str0
  echo Functional test 0 ... 8189 + 8191 with Delayedexpansion OFF ^(create macro^)
  call :func_test
)
echo(done

set "StrLen="
 rem End Test Old
:endTestOld
  if ! gtr ' (echo Delayed OFF) else echo Delayed ON

goto :useOnlyThisVersions
call :initStrLen1    StrLen1
call :initStrLen2    StrLen2
call :initStrLen2i   StrLen2i
call :initStrLen2f   StrLen2f
call :initStrLen2e   StrLen2e
call :initStrLen2d   StrLen2d
call :initStrLen2c   StrLen2c
call :initStrLen2b   StrLen2b
call :initStrLen2z   StrLen2z
:useOnlyThisVersions
call :initStrLen2b   StrLen2b
call :initStrLen2a   StrLen2a
call :initStrLen2y   StrLen2y
call :initStrLen2x   StrLen2x
call :initStrLen2w   StrLen2w
call :initStrlen2v   StrLen2v
call :initStrLenAll
%testecho% pause

::::::: 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 2z 2a 2b 2c 2d 2e all 2f 2i final2 final1" 
set "HeaderInfo=all 2v 2w 2x 2y 2a 2b all" 
set /a times=times_test*7
set /a times_random=20
set /a TABi=0
set "test_StrLength=0 6000 4000 4500 1000 600 200 10 1"
for /f %%0 in ("! '") do (
  if %%0 GTR ' setlocal enabledelayedexpansion
  for /l %%N in (1 1 %times_random%) do (
   for /f %%N in ('set /a !random! %%8191') do set test_StrLength=!test_StrLength! %%N)
  call :testx str1 len %HeaderInfo%
  for %%N in (!test_StrLength!) do (set strX=^
!str1:~,%%~N!
    call :testx strX len %HeaderInfo%
  )
  if %%0 lss ' endlocal
)
pause
goto :eof

:::::::::::::::::::::::::::::::::::::::::::::::::
:func_test
setlocal enabledelayedexpansion
set /a NN=1
:againf_t
set "t1=!time!"
for /L %%L in (0,1,8189) do (
set A=^
!str1:~,%%L!
%strLen% A len
if !len! neq %%L echo  in %%L out !len!
)
%strLen% str1 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

:test
set len=
%strLen% %1 len
echo Check: len=%len%
goto :eof
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:testx
if defined lineX goto :testXnext
:::::::param:   strVar Dummy(writeLen) HeaderInfo
set /a columns=1, tablines=10
::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!
)
:testXnext
set /a i=0
:beginloop
call :loop %*
set /a i+=1,TABi+=1
if !i! lss !columns! goto :beginloop
2>nul set /a X=1/(TABi%%tablines)||echo !linex!&&set "linex="
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]
: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
:pro2i
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2i% %2 len
set t2=!time!
goto :eof
:pro2f
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2f% %2 len
set t2=!time!
goto :eof
:pro2e
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2e% %2 len
set t2=!time!
goto :eof
:pro2d
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2e% %2 len
set t2=!time!
goto :eof
:pro2c
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2c% %2 len
set t2=!time!
goto :eof
:pro2b
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2b% %2 len
set t2=!time!
goto :eof
:pro2a
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2a% %2 len
set t2=!time!
goto :eof
:pro2z
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2z% %2 len
set t2=!time!
goto :eof
:pro2y
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2y% %2 len
set t2=!time!
goto :eof
:pro2x
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2x% %2 len
set t2=!time!
goto :eof
:pro2w
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2w% %2 len
set t2=!time!
goto :eof
:pro2v
set t1=!time!
for /l %%i in (1 1 %1) do %strLen2v% %2 len
set t2=!time!
goto :eof
:proAll
set t1=!time!
for /l %%i in (1 1 %1) do %strLen% %2 len
set t2=!time!
goto :eof
:prolen
set t1=!time!
for /l %%i in (1 1 2) do %strLen2y% %2 len
set t2=!time!
goto :eof

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

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2i
:: 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

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2f
:: 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%%! 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 /f %%# in ("%%!$Scale:~15,1%%!") do set ^"$=%%!$:~0x%%#00%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^"^&^
  for /f %%# 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

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2e
:: 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.
:: this Version is for use only in Batch

    %== ! -> exclamation mark, # -> caret ==%     FOR /F "tokens=1-3" %%! IN (
                                              "! ^! ^ ^^^! . ^^^^") DO ^
set %~1=^
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 %%! neq %%!%%1:~4095%%! (set $L=1^&set $=A%%!%%1:~4096%%!) else ^
  set $L=0^&set $=A%%!%%1%%!)^& 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

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2d
:: 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.
:: this Version is for use only in Batch
    %== ! -> exclamation mark, # -> caret ==%     FOR /F "tokens=1-3" %%! IN (
                                              "! ! ^ ^^^! . ^^^^") DO ^
set %~1=^
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 : neq :%%!%%1:~4095%%! (set $=1%%!%%1:~4096%%!) else ^
  set $=0%%!%%1%%!)^& 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 $=%%!$:~%%#,1%%!%%!$:~0x%%$00%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
  for %%$ in (%%!$:~%%#,1%%!%%$%%!$:~513%%#,1%%!%%!$:~257%%#,1%%!) do (^
  if %%? lss ' endlocal)^&set /A %%~2=0x%%$^
 ) else (if %%? lss ' endlocal)^&set /a %%~2=0^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2c
:: 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.
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! IN (
                                              "! ! ^ ^^^! . ^^^^") DO @^
set %~1=^
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 : neq :%%!%%1:~4095%%! set $=1%%!%%1:~4096%%!^&call)^&^&set $=0%%!%%1%%!^&^
  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 $=%%!$:~%%#,1%%!%%!$:~0x%%$00%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
  (for %%$ in (%%!$:~%%#,1%%!%%$%%!$:~513%%#,1%%!%%!$:~257%%#,1%%!) do (if %%? lss ' endlocal)^&set /A %%~2=0x%%$^
 ) else (if %%? lss ' endlocal)^&set /a %%2=0^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof
 else (if %%? lss ' endlocal)^&set /a %%2=0^

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2b
:: 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.
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! IN (
                                              "! ! ^ ^^^! . ^^^^") DO @^
set %~1=^
for /f %%? in ("%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%! len") do^
 if not defined %%1 (if %%? lss ' endlocal)^&(set /a %%2=0) else^
 (if : neq :%%!%%1:~4095%%! set $=1%%!%%1:~4096%%!^&call)^&^&set $=0%%!%%1%%!^&^
 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 $=%%!$:~%%#,1%%!%%!$:~0x%%$00%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
 for %%$ in (%%!$:~%%#,1%%!%%$%%!$:~513%%#,1%%!%%!$:~257%%#,1%%!) do^
 (if %%? lss ' endlocal)^&set /A %%2=0x%%$^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2a
:: 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.
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! IN (
                                              "! ! ^ ^^^! . ^^^^") DO @^
set %~1=^
for /f %%? in ("%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%! len") do^
 if not defined %%1 (if %%? lss ' endlocal)^&(set /a %%2=0) else^
 (if : neq :%%!%%1:~4095%%! (set $=1%%!%%1:~4096%%!) else set $=0%%!%%1%%!)^&^
 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 $=%%!$:~%%#,1%%!%%!$:~0x%%$00%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
 for %%$ in (%%!$:~%%#,1%%!%%$%%!$:~513%%#,1%%!%%!$:~257%%#,1%%!) do^
 (if %%? lss ' endlocal)^&set /A %%2=0x%%$^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2z
:: 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.
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! IN (
                                              "! ! ^ ^^^! . ^^^^") DO @^
set %~1=^
for /f %%? in ("%%! '") do for %%. in (1 2) do if %%.==2 ^
 for /f tokens%%#=1-2 %%1 in ("%%!$args%%! len") do^
 if not defined %%1 (if %%? lss ' endlocal)^&(set /a %%2=0) else^
 for /f tokens%%#=4%%#,6delims%%#=%%#  %%4 in^
 ("x %%!%%1:~4095,1%%! x%%!%%1:~4095,1%%!x 1 0 4096") do^
 set $=A%%!%%1:~%%5%%!^&set $=%%!$: =.%%!^&^
 for /f usebackqtokens%%#=16delims%%#=%%#  %%3 in (' %%!$:~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%%! F E D C B A 9 8 7 6 5 4 3 2 1 0 ^
 ') do set $=%%!$:~0x%%300%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
 for %%$ in (%%4%%3%%!$:~512%%#,1%%!%%!$:~256%%#,1%%!) do^
 (if %%? lss ' endlocal)^&(set /A %%2=0x%%$^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2y
:: 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.
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! IN (
                                              "! ! ^ ^^^! . ^^^^") DO @^
set %~1=^
for /f %%? in ("%%! '") do for %%. in (1 2) do if %%.==2 ^
 for /f tokens%%#=1-2 %%1 in ("%%!$args%%! len") do^
 if not defined %%1 (if %%? lss ' endlocal)^&(set /a %%2=0) else^
 for /f tokens%%#=4delims%%#=%%#  %%4 in^
 ("x %%!%%1:~4095,1%%! x%%!%%1:~4095,1%%!x 1 0") do set $=A%%!%%1:~0x%%4000%%!^&^
 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 %%3 in (%%!$Scale:~15%%#,1%%!) do set $=%%!$:~0x%%300%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
 for %%$ in (%%4%%3%%!$:~512%%#,1%%!%%!$:~256%%#,1%%!) do^
 (if %%? lss ' endlocal)^&(set /A %%2=0x%%$^
)else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2x
:: 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.
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! IN (
                                              "! ! ^ ^^^! . ^^^^") DO @^
set %~1=^
for /f %%? in ("%%! '") do for %%. in (1 2) do if %%.==2 ^
 for /f tokens%%#=1-2 %%1 in ("%%!$args%%! len") do^
 if not defined %%1 (if %%? lss ' endlocal)^&(set /A %%2=0) else^
 for /f tokens%%#=3delims%%#=%%#  %%4 in (^
 " %%!%%1:~4095,1%%! x%%!%%1:~4095,1%%!x 1 0") do set $=A%%!%%1:~0x%%4000%%!^&^
 for /f tokens%%#=31delims%%#=%%#  %%3 in (^"^
 %%!$:~3840,1%%! x%%!$:~3840,1%%!x %%!$:~3584,1%%! x%%!$:~3584,1%%!x^
 %%!$:~3328,1%%! x%%!$:~3328,1%%!x %%!$:~3072,1%%! x%%!$:~3072,1%%!x^
 %%!$:~2816,1%%! x%%!$:~2816,1%%!x %%!$:~2560,1%%! x%%!$:~2560,1%%!x^
 %%!$:~2304,1%%! x%%!$:~2304,1%%!x %%!$:~2048,1%%! x%%!$:~2048,1%%!x^
 %%!$:~1792,1%%! x%%!$:~1792,1%%!x %%!$:~1536,1%%! x%%!$:~1536,1%%!x^
 %%!$:~1280,1%%! x%%!$:~1280,1%%!x %%!$:~1024,1%%! x%%!$:~1024,1%%!x^
 %%!$:~768,1%%! x%%!$:~768,1%%!x %%!$:~512,1%%! x%%!$:~512,1%%!x^
 %%!$:~256,1%%! x%%!$:~256,1%%!x F E D C B A 9 8 7 6 5 4 3 2 1 0 ^") do^
 set $=%%!$:~0x%%300%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
 for %%$ in (%%4%%3%%!$:~512%%#,1%%!%%!$:~256%%#,1%%!) do^
 (if %%? lss ' endlocal)^&(set /A %%2=0x%%$^
 ) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
@goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2w
:: 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.
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! IN (
                                              "! ! ^ ^^^! . ^^^^") DO @^
set %~1=^
for /f %%? in ("%%! '") do for %%. in (1 2) do if %%.==2 ^
 for /f tokens%%#=1-2 %%1 in ("%%!$args%%! len") do^
 if not defined %%1 (if %%? lss ' endlocal)^&(set /A %%2=0) else^
 for /f tokens%%#=3delims%%#=%%#  %%4 in (^
 " %%!%%1:~4095,1%%! x%%!%%1:~4095,1%%!x 1 0") do^
 for /f tokens%%#=31delims%%#=%%#  %%3 in (^"^
 %%!%%1:~0x%%4eff,1%%! x%%!%%1:~0x%%4eff,1%%!x %%!%%1:~0x%%4dff,1%%! x%%!%%1:~0x%%4dff,1%%!x^
 %%!%%1:~0x%%4cff,1%%! x%%!%%1:~0x%%4cff,1%%!x %%!%%1:~0x%%4bff,1%%! x%%!%%1:~0x%%4bff,1%%!x^
 %%!%%1:~0x%%4aff,1%%! x%%!%%1:~0x%%4aff,1%%!x %%!%%1:~0x%%49ff,1%%! x%%!%%1:~0x%%49ff,1%%!x^
 %%!%%1:~0x%%48ff,1%%! x%%!%%1:~0x%%48ff,1%%!x %%!%%1:~0x%%47ff,1%%! x%%!%%1:~0x%%47ff,1%%!x^
 %%!%%1:~0x%%46ff,1%%! x%%!%%1:~0x%%46ff,1%%!x %%!%%1:~0x%%45ff,1%%! x%%!%%1:~0x%%45ff,1%%!x^
 %%!%%1:~0x%%44ff,1%%! x%%!%%1:~0x%%44ff,1%%!x %%!%%1:~0x%%43ff,1%%! x%%!%%1:~0x%%43ff,1%%!x^
 %%!%%1:~0x%%42ff,1%%! x%%!%%1:~0x%%42ff,1%%!x %%!%%1:~0x%%41ff,1%%! x%%!%%1:~0x%%41ff,1%%!x^
 %%!%%1:~0x%%40ff,1%%! x%%!%%1:~0x%%40ff,1%%!x F E D C B A 9 8 7 6 5 4 3 2 1 0^") do^
 set $=%%!%%1:~0x%%4%%300%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
 for %%$ in (0x%%4%%3%%!$:~511%%#,1%%!%%!$:~255%%#,1%%!) do^
 (if %%? lss ' endlocal)^&(set /A %%2=%%$^
 ) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
@goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2v
:: 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 i=%%!%%1:~03777,1%%!^
 x%%!%%1:~03777,1%%!x&set o=%%!%%1:~0%%4777,1%%! x%%!%%1:~0%%4777,1%%!x^
 %%!%%1:~0%%4377,1%%! x%%!%%1:~0%%4377,1%%!x
set F=FEDCBA9876543210&set $=0000000000000000
   %== ! -> exclamation mark, # -> caret ==%    @FOR /F "tokens=1-3" %%! IN (
                                         "! ! ^ ^^^! . ^^^^") DO ^
set %~1=^
for /f %%? in ("%%! '") do for %%. in (1 2) do if %%.==2 ^
 for /f tokens%%#=1-2 %%1 in ("%%!$args%%! len") do^
 if not defined %%1 (if %%? lss ' endlocal)^&(set /A %%2=0) else^
 for /f "tokens=7,11,15,19delims= " %%4 in (^"^
 %i% %i:3=7% %i:3=13% 17 13 7 3  16 12 6 2  15 11 5 1  14 10 4 0^") do^
 for /f tokens%%#=15delims%%#=%%#  %%3 in (^" %o:4=7% %o:4=6% %o:4=5% %o:*x =%^
 %%44 %%40 %%54 %%50 %%64 %%60 %%74 %%70^") do^
 set $=%%!%%1:~0%%300%%!%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%^
%$:0=F%%$:0=E%%$:0=D%%$:0=C%%$:0=B%%$:0=A%%$:0=9%%$:0=8%^
%$:0=7%%$:0=6%%$:0=5%%$:0=4%%$:0=3%%$:0=2%%$:0=1%%$%^&^
 for %%$ in (0%%300+0x0%%!$:~511%%#,1%%!%%!$:~255%%#,1%%!) do^
 (if %%? lss ' endlocal)^&(set /A %%2=%%$^
 ) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
for %%i in (i o F $) do set "%%i="
@goto :eof

 in Arbeit ....
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2u
:: 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 i=%%!%%1:~03777,1%%!^
 x%%!%%1:~03777,1%%!x&set o=%%!%%1:~0%%4777,1%%! x%%!%%1:~0%%4777,1%%!x^
 %%!%%1:~0%%4377,1%%! x%%!%%1:~0%%4377,1%%!x
set F=FEDCBA9876543210&set $=0000000000000000
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! IN (
                                              "! ! ^ ^^^! . ^^^^") DO ^
set %~1=^
@for /f %%? in ("%%! '") do @for %%. in (1 2) do if %%.==2 ^
 @for /f tokens%%#=1-2 %%1 in ("%%!$args%%! len") do^
 if not defined %%1 @(if %%? lss ' endlocal)^&(set /A %%2=0) else^
 for /f "tokens=7,11,15,19delims= " %%4 in (^"^
 %i% %i:3=7% %i:3=13% 17 13 7 3  16 12 6 2  15 11 5 1  14 10 4 0^") do^
 for /f tokens%%#=15delims%%#=%%#  %%3 in (^" %o:4=7% %o:4=6% %o:4=5% %o:*x =%^
 %%44 %%40 %%54 %%50 %%64 %%60 %%74 %%70^") do^
 set $=%%!%%1:~0%%300%%!%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%^
%$:0=F%%$:0=E%%$:0=D%%$:0=C%%$:0=B%%$:0=A%%$:0=9%%$:0=8%^
%$:0=7%%$:0=6%%$:0=5%%$:0=4%%$:0=3%%$:0=2%%$:0=1%%$%^&^
 for %%$ in (0%%300+0x0%%!$:~511%%#,1%%!%%!$:~255%%#,1%%!) do^
 (if %%? lss ' endlocal)^&(set /A %%2=%%$^
 ) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
for %%i in (i o F $) do @set "%%i="
@goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLenAll
:: 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 i=%%!%%1:~03777,1%%!^
 x%%!%%1:~03777,1%%!x&set o=%%!%%1:~0%%4777,1%%! x%%!%%1:~0%%4777,1%%!x^
 %%!%%1:~0%%4377,1%%! x%%!%%1:~0%%4377,1%%!x
@set F=FEDCBA9876543210&set $=0000000000000000
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! 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 not defined %%1 (if %%? lss ' endlocal)^&(set /A %%2=0) else^
 for /f "tokens=7,11,15,19delims= " %%4 in (^"^
 %i% %i:3=7% %i:3=13% 17 13 7 3  16 12 6 2  15 11 5 1  14 10 4 0^") do^
 @for /f tokens%%#=15delims%%#=%%#  %%3 in (^" %o:4=7% %o:4=6% %o:4=5% %o:*x =%^
 %%44 %%40 %%54 %%50 %%64 %%60 %%74 %%70^") do^
 @set $=%%!%%1:~0%%300%%!%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%%F%^
%$:0=F%%$:0=E%%$:0=D%%$:0=C%%$:0=B%%$:0=A%%$:0=9%%$:0=8%^
%$:0=7%%$:0=6%%$:0=5%%$:0=4%%$:0=3%%$:0=2%%$:0=1%%$%^&^
 for %%$ in (0%%300+0x0%%!$:~511%%#,1%%!%%!$:~255%%#,1%%!) do^
 @(if %%? lss ' endlocal)^&(set /A %%2=%%$^
 ) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
@for %%i in (i o F $) do @set "%%i="
@goto :eof

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initTimediff  
::: 32 characters shortened
FOR /F "tokens=1-3" %%! IN ("! ! ^ ^^^! . ^^^^") DO %== ! -> exclamation mark, # -> caret ==%^
set timediff=for /f %%? in ("%%! '") do for /l %%0 in (1 1 2) do if %%0 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 %%! equ %%/ (echo %%') else set %%/=%%') else (if %%? GTR ' setlocal enabledelayedexpansion)^&set _i_=
goto :eof

CMD and Batch Version

Code: Select all

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLenAll
:: 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.
:: This Version is for use in CMDline and Batch
                                                @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 /f %%# in ("%%!$Scale:~15,1%%!") do @set $=%%!$:~0x%%#00%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
  for /f %%# 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
Last edited by pieh-ejdsch on 18 Aug 2025 12:47, edited 6 times in total.

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

Re: strLen boosted

#66 Post by pieh-ejdsch » 07 Aug 2025 12:26

@Francesco

Here is a brief summary of the steps again.

The things I changed were:
Converting the use of For variables into hard-coded delayed normal variables as early as possible.
Since For variables can be used well as name storage,
but expanding the For variable within exclamation marks takes time to resolve this name,
it is better to resolve the variable without the name storage of the For.

Use if and else as little as possible. Resolve double if queries differently.
I tried moving the else to the top, but the time did not get shorter—rather longer...

I never filled the variables with empty values, as empty variables only cause problems with expansion.
And I don't need to check whether it is filled.

The icing on the cake was the use of hexadecimal code for variable expansion—it runs a little slower,
but if I can save a Set /a statement with it, then the code is faster than before.
This means that only one Set /a statement is executed.
I have already considered removing the 0x from the search loop and inserting it directly into the Set /a statement,
which would make the For variable two characters shorter.
As you know, every little bit helps! (in German we say: Du weißt ja, Kleinvieh macht auch Mist!)

Only use extended for variables WITHOUT (i.e., as far as possible) enclosing quotation marks,
i.e., make sure that the literal string does not enclose quotation marks
[for /f %i in (“xyz”) do ...] or [for %i in (xyz) do ...].
Removing the quotation marks takes more time.

[edit]
Oh, and I almost forgot to mention —
the closing brackets and the Command Chaining
[ ) & && | || ]
must be added directly to the set statements without enclosing quotation marks.
Otherwise, an additional character will be included in the variable.
To do this, it must be written on the same line so that the line break is not inserted.
[/edit]

This led me to the special character handling in the variable representation.
So escape the comma to save the quotation marks.
The creation of the macro now takes this into account.

If no variable expansion with special characters is performed,
assign the variable without quotation marks.
These are delayed variables.

Also, do not use quotation marks in comparisons unless necessary.

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

Re: strLen boosted

#67 Post by aGerman » 08 Aug 2025 14:11

Your HEX magic is incredible :lol: Also for short strings it's now only negligibly slower. The performance gain for longer string is remarkable though.

That's how I'm going to save it into my tool collection:

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, Optional] Name of the variable that receives the measured
::         length. If omitted, the result is assigned to variable len.
::   Variable names must be passed unquoted.
:: Strings of up to 8191 characters are supported.
      %== ! -> exclamation mark, # -> caret ==%     FOR /F "TOKENS=1-3" %%! IN (
                                                        "! ! ^ ^^^! . ^!=^!^^^^"
                                         ) DO FOR %%H IN (FEDCBA9876543210) 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 %%! equ %%!%%1:~4095%%#,1%%! (set /a $4K=0^&set $=A%%!%%1%%!) ^
%=     =% else set /a $4K=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%%!%%H^&^
%=    =% for %%_ in (%%!$Scale:~15%%#,1%%!) do set $=^
%=     =%%%!$:~0x%%_00%%!%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H%%H^
%=     =%FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
%=     =%BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
%=     =%7777777777777777666666666666666655555555555555554444444444444444^
%=     =%3333333333333333222222222222222211111111111111110000000000000000^&^
%=    =% for %%- in (0x%%!$4K%%!%%_%%!$:~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
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
I didn't change anything in the logic. Ultimatively, still the four-digit hex value is evaluated, like 0xWXYZ with ...
W - !$4K! = multiples of 4096 [0,1]
X - %%_ = !$Scale:~15,1! = multiples of 256 [0..F]
Y - !$:~512,1! = multiples of 16 [0..F]
Z - !$:~256,1! = multiples of 1 [0..F] ([1..F] if WXY is 000, since empty strings are excluded early)

Steffen

EDIT Slightly updated:
- $L did not contain the length anymore, but the hex digit for the 4096 portion (like the 1 in 0x1000). Renamed to $4K.
- %%$ was used twice in nested FOR loops. That's triple confusing as we also have the $ env. variable. To at least have distinct names, renamed to %%_ and %%-, respectively.
- %==% like indentations added, even though they are not quite nice and we still have to keep the closing parenthesis at the end of a SET statement.

EDIT2 Also updated the generation of %%! and %%# as mentioned in the next post.

EDIT3 Fix for caret expansion taken over that jeb pointed out.

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

Re: strLen boosted

#68 Post by pieh-ejdsch » 10 Aug 2025 07:41

I have made the creation of the exclamation mark and caret a little shorter, which happens before the macro is created.

Code: Select all

FOR /F "tokens=1-3" %%! IN ("! ! ^ ^^^! . ^^^^") DO ^
It looks a little strange, but since the first caret disappears in delayed expansion, it can already be used as the third token.

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

Re: strLen boosted

#69 Post by aGerman » 10 Aug 2025 08:06

I would never have thought of that :lol:
FWIW You could also update this in your previous codes. When you're logged in, you'll see an edit button (pencil) at the top of each of your posts. (Although it doesn't matter if not. The content of the strLen macro is not affected, only its initialization.)

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

Re: strLen boosted

#70 Post by jeb » 11 Aug 2025 05:49

pieh-ejdsch wrote:
10 Aug 2025 07:41
I have made the creation of the exclamation mark and caret a little shorter, which happens before the macro is created.

Code: Select all

FOR /F "tokens=1-3" %%! IN ("! ! ^ ^^^! . ^^^^") DO ^

It looks a little strange, but since the first caret disappears in delayed expansion, it can already be used as the third token.
There is a small flaw: it fails when a caret is on a single line and delayed expansion is enabled.
See the difference here.

Code: Select all

@echo off

setlocal DisableDelayedExpansion

call :test DisableDelayedExpansion
call :test EnableDelayedExpansion

exit /b

:test
echo --- %1
setlocal %1
FOR /F "tokens=1-4" %%! IN ("! ! ^ ^^^! . ^^^^ a b") DO (
    echo bang %%! -
    echo caret %%# -
    echo caret bang %%! %%# -
    endlocal
    echo percent-percent-bang  '%%!'
    echo percent-percent-caret '%%#'
)
The line with a single caret expands to two carets in delayed expansion mode

Code: Select all

--- DisableDelayedExpansion
bang ! -
caret ^ -
caret bang ! ^ -
percent-percent-bang  '!'
percent-percent-caret '^'
--- EnableDelayedExpansion
bang ! -
caret ^^ -
caret bang ! ^ -
percent-percent-bang  '^!'
percent-percent-caret '^^'
This can be fixed by adding !=! to the carets.

Code: Select all

FOR /F "tokens=1-4" %%! IN ("! ! ^ ^^^! . ^!=^!^^^^ a b") DO 

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

Re: strLen boosted

#71 Post by aGerman » 11 Aug 2025 13:23

Yes, of course, I fully understand why it works ... not 🤪🥴
I get why you use !=! since this can't ever be a defined variable. However what puzzles me is why it even makes any difference if it comes before the caret (or after it, as this seems to work too).
Anyway, I just accept it :lol:

Steffen

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

Re: strLen boosted

#72 Post by jeb » 11 Aug 2025 13:54

aGerman wrote:
11 Aug 2025 13:23
However what puzzles me is why it even makes any difference if it comes before the caret (or after it, as this seems to work too).
It forces the delayed expansion phase to trigger.
The delayed expansion phase only have an effect, when at least one exclamation mark is in the line (and it must still be present in that phase)

Code: Select all

setlocal EnableDelayedExpansion
echo #1 cd=!cd!
echo #2 Will the delayed expansion phase be executed here?
echo #3 But here you can see differences one caret ^^ "and one inside quotes ^"
echo #4 And now with a useless !=!       ... one caret ^^ "and one inside quotes ^"
echo #5 Or at the end ... one caret ^^ "and one inside quotes ^" .... !
for %%! in ("dummy") do (
  echo #6 %%! ... one caret ^^ "and one inside quotes ^"
)
Output:

Code: Select all

#1 cd=C:\somewhere\batch
#2 Will the delayed expansion phase be executed here?
#3 But here you can see differences one caret ^ "and one inside quotes ^"
#4 And now with a useless        ... one caret  "and one inside quotes "
#5 Or at the end ... one caret  "and one inside quotes " .... 
#6 "dummy" ... one caret ^ "and one inside quotes ^"
So, if you want to define a macro and use the %%# to add a single caret,
it should always be just one caret,
regardless of whether there are exclamation marks in the line or not.

However, there is one more small thing.
It is also important that the command and the arguments are evaluated separately for delayed expansion.

Code: Select all

echo:!  arg ^^ "^" shows carets
echo:!^^^^ caret ^^
echo:^^^^ caret ^^!
Output

Code: Select all

arg ^ "^" shows carets
^ caret ^
^^ caret !

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

Re: strLen boosted

#73 Post by aGerman » 11 Aug 2025 14:56

So, we define that delayed expansion is enabled but the cmd may gives us the finger :lol:
Like if I go to a hardware store to buy an 8mm nut, but the shop assistant decides that I only get one if I can show the matching screw :roll:
Got it. Thanks!

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

Re: strLen boosted

#74 Post by pieh-ejdsch » 12 Aug 2025 04:47

OK! Strange that the macro still works. Regardless of whether I have delayed ON or OFF during creation or execution.

Well, that gave me the idea to include the colon in the first comparison instead of using the exclamation mark.
Because the single exclamation mark is not [empty] in the CMD line (with CMD/V),
but that doesn't affect the macro, because the macro has to be executed in the CMD line under CMD/v.

Then I removed two (actually one) variable(s) from the script.
It doesn't make it any faster, but the variant – which was intended for the CMD line – no longer has quotation marks and also runs faster in batch than the other versions.
Only 63 percent of the execution time of final2 and 5 percent less than the previous version.

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.
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! 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 : neq :%%!%%1:~4095%%! (set $=1%%!%%1:~4096%%!) else ^
  set $=0%%!%%1%%!)^& 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 $=%%!$:~%%#,1%%!%%!$:~0x%%$00%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
  for %%$ in (%%!$:~%%#,1%%!%%$%%!$:~513%%#,1%%!%%!$:~257%%#,1%%!) do @(^
  if %%? lss ' endlocal)^&set /A %%~2=0x%%$^
 ) else (if %%? lss ' endlocal)^&set /a %%~2=0^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
@goto :eof
The only difference to the batch variant is that it does not contain any @ characters – but the batch variant is slightly slower...

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

Re: strLen boosted

#75 Post by pieh-ejdsch » 13 Aug 2025 10:34

New macro

[edit]I played around with the command chain a bit and sped up an if else (which no longer has an else).
You should check it again with the old (rejected) code.
It didn't run any faster—I had changed too much at once.[/edit]
The penultimate else has now been moved up.
This has eliminated a pair of brackets.
There is now no more space to fill with empty spaces.
The previous script versions have been left in the test code;
this was only expanded for testing purposes and the old functioning version was left in place.
(Normally, non-functioning versions must also be left in place and marked accordingly).
But who wants to show bad code...


In post #65, I adjusted the test code. The check runs with delayed ON and delayed OFF.

script

Code: Select all

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:initStrLen2a
:: 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.
    %== ! -> exclamation mark, # -> caret ==%     @FOR /F "tokens=1-3" %%! IN (
                                              "! ! ^ ^^^! . ^^^^") DO @^
set %~1=^
for /f %%? in ("%%! '") do for %%. in (1 2) do if %%.==2 (^
 for /f "tokens=1,2" %%1 in ("%%!$args%%! len") do^
 if not defined %%1 (if %%? lss ' endlocal)^&(set /a %%2=0) else^
 (if : neq :%%!%%1:~4095%%! (set $=1%%!%%1:~4096%%!) else set $=0%%!%%1%%!)^&^
 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 $=%%!$:~%%#,1%%!%%!$:~0x%%$00%%!^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210^
FFFFFFFFFFFFFFFFEEEEEEEEEEEEEEEEDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCC^
BBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA99999999999999998888888888888888^
7777777777777777666666666666666655555555555555554444444444444444^
3333333333333333222222222222222211111111111111110000000000000000^&^
 for %%$ in (%%!$:~%%#,1%%!%%$%%!$:~513%%#,1%%!%%!$:~257%%#,1%%!) do^
 (if %%? lss ' endlocal)^&set /A %%2=0x%%$^
) else (if %%? GTR ' setlocal enabledelayedexpansion)^&set $args=
goto :eof
Without the check for empty variables, it would be even faster—but I'm not going any further here.
Last edited by pieh-ejdsch on 13 Aug 2025 14:32, edited 2 times in total.

Post Reply