Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Get String Length

82 views
Skip to first unread message

Tom Del Rosso

unread,
Sep 1, 2021, 3:30:21 PM9/1/21
to
Here's a subroutine to get the length of a string that uses successive
approximation so it runs very fast because it only loops 13 times (once
for each bit of the resulting number) no matter how long the string is.


:GetStringLength
rem Takes string variable NAME which must have no spaces. Returns
variable: StringLength
rem Environment variables go up to 8191 characters so approximation
starts with 4096 which is the MSB.
rem Practical limit is 8185 because "set x=" has 6 characters
if [%1]==[] set "StringLength=" & goto :eof
if not defined %1 set /a StringLength=0 & goto :eof
set /a GetStringLength_PlaceValue=4096
set /a GetStringLength_Guess=0
:GetStringLength_Loop
set /a GetStringLength_Guess^|=GetStringLength_PlaceValue
set /a GetStringLength_Skip=GetStringLength_Guess-1
call set "GetStringLength_Char=%%%1:~%GetStringLength_Skip%,1%%"
if not defined GetStringLength_Char set /a
GetStringLength_Guess^^=GetStringLength_PlaceValue
set /a GetStringLength_PlaceValue/=2
if %GetStringLength_PlaceValue% GTR 0 goto :GetStringLength_Loop
set /a StringLength=GetStringLength_Guess
set "GetStringLength_String="
set "GetStringLength_PlaceValue="
set "GetStringLength_Guess="
set "GetStringLength_Skip="
set "GetStringLength_Char="
goto :eof



Tom Del Rosso

unread,
Sep 1, 2021, 3:39:22 PM9/1/21
to
Oops the REM lines wrapped and one other line did:

JJ

unread,
Sep 2, 2021, 12:13:23 AM9/2/21
to
On Wed, 1 Sep 2021 15:30:18 -0400, Tom Del Rosso wrote:
> Here's a subroutine to get the length of a string that uses successive
> approximation so it runs very fast because it only loops 13 times (once
> for each bit of the resulting number) no matter how long the string is.
[snip]

Nice. Would definitely be part of by batch subs library.

The method could be used as a fast `HasStr` sub. :)

Tom Del Rosso

unread,
Sep 2, 2021, 2:55:35 AM9/2/21
to
I just noticed that there is a vestigial line still in there.

Remove this:

set "GetStringLength_String="



Tom Del Rosso

unread,
Sep 2, 2021, 3:08:04 AM9/2/21
to
What does HasStr do? Find a substring?


--
Defund the Thought Police


Harry Potter

unread,
Sep 2, 2021, 3:49:21 PM9/2/21
to
JJ, I have a batch file that backs up a user program without rebuildable files to a specified folder using 7Zip and one that returns the current date. The former is hard-coded for my needs but can be customized by other downloaders, and the latter simply returns the current date in the environment variable %DATE2%. The former first asks for the subfolder (I call it the system, as that is how I organize my backups, but you can change the prompt text.) then makes a temporary copy of the program, deletes rebuildable files (mainly programs and object files), compresses the folder, attaches the date to the name, moves the file to the destination and then deletes the temporary folder. Are you interested? If so, I ask for a way to send you the files in any way you like. I have some information on sourceforge.net and can upload them there, or I can e-mail you the files.

BTW, I have other batch files that I use. I'll look at them now.

Harry Potter

unread,
Sep 2, 2021, 4:11:41 PM9/2/21
to
On Thursday, September 2, 2021 at 3:49:21 PM UTC-4, Harry Potter wrote:
> JJ, I have a batch file that backs up a user program without rebuildable files to a specified folder using 7Zip and one that returns the current date. The former is hard-coded for my needs but can be customized by other downloaders, and the latter simply returns the current date in the environment variable %DATE2%. The former first asks for the subfolder (I call it the system, as that is how I organize my backups, but you can change the prompt text.) then makes a temporary copy of the program, deletes rebuildable files (mainly programs and object files), compresses the folder, attaches the date to the name, moves the file to the destination and then deletes the temporary folder. Are you interested? If so, I ask for a way to send you the files in any way you like. I have some information on sourceforge.net and can upload them there, or I can e-mail you the files.
>
> BTW, I have other batch files that I use. I'll look at them now.

I looked at the batch files. They are mostly for my work with emulation, but I have some batch files to compress folders using 7Zip or WInMount to specific locations and assemble a code file to a .COM file using NASM. Is anybody interested?

Harry Potter

unread,
Sep 2, 2021, 4:18:51 PM9/2/21
to
I also have two batch files to compress executables using UPX, one to compress files to .gz files using 7Zip and one that automatically decompresses archives to a specific folder.

Harry Potter

unread,
Sep 2, 2021, 4:31:52 PM9/2/21
to
The easiest way to use them is to add them to the SendTo folder using SendTo Toys. You can find it on freewarefiles.com.

JJ

unread,
Sep 3, 2021, 1:11:26 AM9/3/21
to
Yes. A sub to check the existence of a substring when the index of the
substring doesn't matter. It's basically just a sub which finds the index of
a substring.

Tom Del Rosso

unread,
Sep 3, 2021, 3:07:21 AM9/3/21
to
So you're thinking of doing it this way?


@echo off
set string=Where is the substring?
set substring=the

call set poststring=%%string:*%substring%=%%

call :GetStringLength string
set /a string_len = StringLength
call :GetStringLength substring
set /a substring_len = StringLength
call :GetStringLength poststring
set /a poststring_len = StringLength

set /a position = string_len - substring_len - poststring_len

echo %string%
echo %substring%
if %poststring_len% LSS %string_len% echo Has string after position
%position%.

pause
goto :eof

Robert Prins

unread,
Sep 3, 2021, 5:47:05 AM9/3/21
to
We're living in 2021, why write convoluted code when there are much better
languages to do this? REXX (available for about every OS) can do it in one line,
and if you only use Windoze, PowerShell would probably do it.

Robert
--
Robert AH Prins
robert(a)prino(d)org
The hitchhiking grandfather - https://prino.neocities.org/indez.html
Some REXX code for use on z/OS - https://prino.neocities.org/zOS/zOS-Tools.html

Kenny McCormack

unread,
Sep 3, 2021, 4:20:49 PM9/3/21
to
In article <sgsqun$h78$1...@dont-email.me>,
Robert Prins <rob...@prino.org> wrote:
...
>We're living in 2021, why write convoluted code when there are much better
>languages to do this? REXX (available for about every OS) can do it in one line,
>and if you only use Windoze, PowerShell would probably do it.

Because those are the rules of this newsgroup. Like several other Usenet
newsgroups, this group is kind of an abstraction. I.e., the issue isn't
solving specific problems by whatever means work - i.e., if it works, it is
good mentality. Rather, it is solving the problem using only a specific
set of tools - sort of like "straight edge and compass" problems in
geometry.

The rules - which, BTW, I didn't make up, and I, of course, have no
authority to enforce, but which I have gleaned from years of observing this
group - is that you can only solve problems using functionality found in
CMD.EXE itself (and COMMAND.COM before then). You are not allowed to use
any external tools or languages. To do so would be cheating.

Note, BTW, that you are sort of allowed (wink, wink, nudge, nudge) to cheat
semi-legally by using things like WishScript, or JavaScript, or
WhateverScript or PowerShell, because you can sort of make a case that
these things are now builtin on most modern Windows installs. But the
point is that most people still using DOS/Windows (without any external
tools) are probably doing so on older machines (I still have several XP
machines), and those tools won't be present on those older machines.

In fact, many of the people still using CMD.EXE batch language, are
probably running their PCs by oil light, in a cave somewhere in Afghanistan
(or similar).

BTW, REXX? Seriously???

--
"Only a genius could lose a billion dollars running a casino."
"You know what they say: the house always loses."
"When life gives you lemons, don't pay taxes."
"Grab 'em by the p***y!"

Zaidy036

unread,
Sep 3, 2021, 5:23:15 PM9/3/21
to
another batch:

:: _StrngLen.bat

:: _StrngLen.bat "string" Length at exit
:: _StrngLen.bat "string" _Len Variable for length
:: https://ss64.com/nt/syntax-strlen.html

@ECHO OFF
ECHO(
FOR %%F IN (%1 %2 %3 %4 %5 %6 %7 %8 %9) DO CALL :LnCalc %%F

:EOF

:LnCalc
Setlocal EnableDelayedExpansion
:: strLen String [RtnVar]
:: -- String The string to be measured, surround in quotes
if it contains spaces.
:: -- RtnVar An optional variable to be used to return the
string length.
ECHO(
SET "s=#%~1"
SET "len=0"
For %%N in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if "!s:~%%N,1!" neq "" (
SET /a "len+=%%N"
SET "s=!s:~%%N!"
)
)
:: Endlocal & IF "%~2" neq "" (SET %~2=%len%) else ECHO %len% of %1
Endlocal & ECHO %len% of %1
GOTO :EOF

Zaidy036

unread,
Sep 3, 2021, 6:00:13 PM9/3/21
to

Tom Del Rosso

unread,
Sep 3, 2021, 10:26:12 PM9/3/21
to
Robert Prins wrote:
>
> We're living in 2021, why write convoluted code when there are much
> better languages to do this? REXX (available for about every OS) can
> do it in one line, and if you only use Windoze, PowerShell would
> probably do it.

You can also do it with one line in a batch file like so:

call :GetStringLength

Everyone here knows other languages. We use batch when it's the best
choice.

If it's never the best choice for you, then you wouldn't have come here.

BTW REXX was included in OS/2 in 1993. I was an advocate. No one
listened. Since you emphasize that it's 2021 you probably should have
suggested Python.

And also, successive approximation isn't convoluted. It has a lot of
applications. There are successive approximation register chips that do
it in hardware for A/D conversion. My method was IMO very
straightforward and readable, and I'm a fan of Knuth's law, "A program
should be readable by humans first and computers second."



Tom Del Rosso

unread,
Sep 4, 2021, 2:49:42 AM9/4/21
to
Another way to do successive approximation. And it's probably faster.
Did you just write that?

JJ

unread,
Sep 4, 2021, 5:46:55 AM9/4/21
to
On Fri, 3 Sep 2021 03:07:18 -0400, Tom Del Rosso wrote:
> JJ wrote:
>> On Thu, 2 Sep 2021 03:08:01 -0400, Tom Del Rosso wrote:
>>>
>>> What does HasStr do? Find a substring?
>>
>> Yes. A sub to check the existence of a substring when the index of the
>> substring doesn't matter. It's basically just a sub which finds the
>> index of a substring.
>
> So you're thinking of doing it this way?
[snip]

Huh? Why are you using string lengths to check the existence of a substring?

Zaidy036

unread,
Sep 4, 2021, 11:56:22 AM9/4/21
to

Tom Del Rosso

unread,
Sep 5, 2021, 12:53:22 PM9/5/21
to

JJ

unread,
Sep 6, 2021, 3:08:00 AM9/6/21
to
By "method", I meant the algorithm. Not the sub itself as is.

But nevermind though, cause I found out that the divide-and-conquer
algorithm can't be used as a faster substring search than sequential one.

Tom Del Rosso

unread,
Sep 6, 2021, 12:45:49 PM9/6/21
to
If the objective is to find exactly where the substring exists then it
could actually be faster for a long string.

I mean using the asterisk in string substitution like below, and testing
the length of the result. Even more so if you already know the length of
the original string.

call set poststring=%%string:*%substring%=%%



JJ

unread,
Sep 7, 2021, 7:24:45 AM9/7/21
to
Oh, I see. I didn't realize asterisk as a leading wildcard is supported for
string replacement. That's indeed a faster way to find the substring offset.
Thanks.

Though, in a different topic but related to that asterisk wildcard...
Although I haven't yet need to do it, is it possible to replace literal
asterisk character itself excluding any characters preceeding it, using
replace string substitution? I've tried escaping the asterisk and using
double asterisks, but it doesn't work. For example, to replace `*` with `;`,
so that e.g. `abc*def` would become `abc;def`.

@echo off
setlocal
call :repesc "abc*def" result
echo escape=%result%
call :repdbl "abc*def" result
echo double=%result%
goto :eof

:repesc
set "a=%~1"
set "%2=%a:^*=;%"
goto :eof

:repdbl
set "a=%~1"
set "%2=%a:**=;%"
goto :eof

Here, the result are:

escape=abc*def
double=;def

mokomoji

unread,
Sep 7, 2021, 12:34:34 PM9/7/21
to
2021년 9월 4일 토요일 오전 6시 23분 15초 UTC+9에 Zaidy036님이 작성한 내용:
@echo off
setlocal
Set "_demo=some example string don with enabledelayedexpansion version"
Call :strlen "_length" "%_demo%"
Echo String is %_length% characters long
goto :end

:strlen
set "s=#%~2"
set "len=0"
for %%N in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
for /f "delims=" %%f in ('echo "%%s:~%%N,1%%"') do (
if "%%~f" neq "" (
call set /a "len+=%%N"
call set "s=%%s:~%%N%%"
rem call echo %%f %%N %%s%%
)))
if "%~1" neq "" (set %~1=%len%) else (echo %~1 = %%%~1%%)
goto :eof

:end
endlocal
pause


god them..~!!

Tom Del Rosso

unread,
Sep 7, 2021, 5:10:40 PM9/7/21
to
I guess you could use ** to chop off the first part of the string, then
measure its length and then reassemble it, like

set x=abc*def
set y=%x:**=;%
[...get length of x and y and x-y...]
set /a prefix_len = x_len - y_len
call set z=%%x:~0,%prefix_len%%%%y%
set z
pause


But my first idea started in the wrong direction.
I thought of putting something before the asterisk like

set y=%x:c*=c;%

which would work if you know the letter before it is c.

To try every letter you have to use FIND to do the substitution at the
right time (or else it would change back when it got to the next
letter), like this, but it's much slower.

@echo off
set y=abc*def
set "z="
for %%a in (a b c d e f g h i j k l m n o p q r s t u v w x y z) do (
echo %y% | find "%%a*" >nul
if not errorlevel 1 (
call set z=%%y:%%a*=%%a$%%
)
)
set y
set z
pause
0 new messages