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

Extension of string count foxidrive posted in July

7 views
Skip to first unread message

Tom Lavedas

unread,
Nov 17, 2009, 9:24:11 AM11/17/09
to
For some reason google won't let me add a reply to this thread (too
old?):

http://groups.google.com/group/alt.msdos.batch.nt/browse_frm/thread/f5aa5405d3252bd6/28256f8fd5bc2d24?#28256f8fd5bc2d24.

In particular, I wanted to comment on an approach that foxidrive
posted in response to something I posted. His approach used a trick
of the command processor, cmd.exe, to parse a string and then count
its length using the FIND utility. However, the approach as
formulated had problems with spaces in the string. I loved the way it
used a documented feature of the command to create an undocumented
capability, so I played with it and created this simpler variation to
determine the length of a string ...

@echo off
for /f %%l in ('cmd/u/cecho/"%~1"^|find /v /c ""'
) do set /a CNT=%%l-5
echo %cnt%

It replaces the /n (number) switch in the find with the /c (count) and
thereby appears to have resolved the problem of spaces. However, what
I realized recently is that retaining the /n and adding a second
argument gives a routine that finds the position of any single
character within the string, that is ...

@echo off
set pos=0
for /f "delims=[]" %%l in ('cmd/u/cecho/"%~1"^|find /n "%~2"'
) do set /a pos=%%l-1
echo The position of %2 is %pos%

So if the routine is passed a string of 12345.7890 and a second
argument of a dot, the result would be ...

The position of . is 6

As written, it finds the first occurrence, returns zero if there is no
match and can only match a single character, but I thought it was
still interesting in its simplicity.
_____________________
Tom Lavedas

Frank P. Westlake

unread,
Nov 17, 2009, 9:57:17 AM11/17/09
to
"Tom Lavedas"
news:f88c6bad-9e85-4e02...@l2g2000yqd.googlegroups.com...

> As written, it finds the first occurrence, returns zero if there is no
> match and can only match a single character, but I thought it was
> still interesting in its simplicity.

It looks like it could be very useful for changing number bases. Here's
a quick example using hex to decimal:

:: BEGIN SCRIPT :::::::::::::::::::::::::::::::
@Echo OFF
SetLocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
Set "HexStr=0123456789ABCDEF"
Set "DecValue=0"
Set "HexValue=7D9"
Call :HexToDec
Set DecValue

Goto :EOF
:HexToDec
set pos=-1


for /f "delims=[]" %%l in (

'cmd/u/cecho/"%HexStr%"^|find /n "%HexValue:~0,1%"'
) do set /a pos=%%l-2
If %pos% LSS 0 Goto :EOF
Set /A "DecValue=DecValue*16+pos
Set "HexValue=%HexValue:~1%"
If DEFINED HexValue Call :HexToDec
Goto :EOF
:: END SCRIPT :::::::::::::::::::::::::::::::::

I don't immediately recall how I normally do that si I don't know if
this fastr than other methods, but it certainly is useful,

Thanks.

Frank


Frank P. Westlake

unread,
Nov 17, 2009, 10:36:28 AM11/17/09
to
"Frank P. Westlake" news:hdudkf$rar$1...@news.albasani.net...

> It looks like it could be very useful for changing number
> bases. Here's

The example I gave is a bad one because hex to decimal is more easily
done with 'SET/A dec=0x%HEX%', but that is the only conversion it will
do. Your routine can also be used to convert bases which are constructed
with symbols, such as '&'.

The example I gave deconstructs the hex variable until it gets to the
first unrecognized character and leaves the remainder in the variable.
So 'HexStr=7D9YEARS' would be left with "YEARS".

Frank


Tom Lavedas

unread,
Nov 17, 2009, 1:23:52 PM11/17/09
to
On Nov 17, 10:36 am, "Frank P. Westlake" <frank.westl...@yahoo.com>
wrote:

You got me started. Here is a decimal to hex converter that works for
positive integers up to 2^32 - 1 ...

:: Decimal to Hex conversion
@echo off
setlocal
set /a "d=%~1" >nul 2>&1
if not defined d goto :EOF
set base=16
set "h="
:Loop
set /a t=d%%base
if %t% gtr 9 for /f "tokens=2delims=]" %%a in (
'cmd/u/cecho.123456789abcdef^|find /n /v ""^|find "[%t%]"'
) do set "t=%%a"
set "h=%t%%h%"
set /a d/=base
if %d% GTR 0 goto :Loop
set /a d=0x%h%
echo %d% decimal = 0x%h%

The one statement parser performs a quick table lookup of the digits
above 0-9.

Actually, by adjusting the variable 'base', it works for any base up
to hex (except for the problems with the last two lines, which I added
for illustration). Adding some more letters to the FOR statement
would accommodate higher bases, if wanted. But, that's just an
academic exercise, I suppose.
_____________________
Tom Lavedas

Frank P. Westlake

unread,
Nov 17, 2009, 3:11:02 PM11/17/09
to
"Tom Lavedas"
news:42bac7c0-d45e-4642...@a21g2000yqc.googlegroups.com...

> Here is a decimal to hex converter ...

And here a base n to decimal converter for bases 2 to 36. The demo
converts 2147483647 in bases 2, 16, and 36 to base 10. The base 2
conversion has to deal with 31 digits and you can see that it takes a
while. This version does not deconstruct the original variable and
doesn't need the result variable to be initialized with 0.

:: BEGIN SCRIPT :::::::::::::::::::::::::::::::
@Echo OFF
SetLocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION

REM All three of these equal 2147483647 decimal.
::Base 2
Set "OldValue=1111111111111111111111111111111"
Call :BaseToDec 2 OldValue NewValue
Set NewValue
::Base 16
Set "OldValue=7FFFFFFF"
Call :BaseToDec 16 OldValue NewValue
Set NewValue
::Base 36
Set "OldValue=ZIK0ZJ"
Call :BaseToDec 36 OldValue NewValue
Set NewValue

Goto :EOF
:BaseToDec BaseNumber SourceVariableName DestinationVariableName
SetLocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
Set "new=0"
Set "CharSet=0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
:BaseToDec.repet


set pos=-1
for /f "delims=[]" %%l in (

'cmd/u/cecho/"!CharSet:~0,%1!"^|find /n "!%2:~0,1!"'


) do set /a pos=%%l-2
If %pos% LSS 0 Goto :EOF

Set /A "new=new*%1+pos
Set "%2=!%2:~1!"
If DEFINED %2 Goto %0.repet
EndLocal&Set "%3=%new%"
Goto :EOF
:: END SCRIPT :::::::::::::::::::::::::::::::::

Frank


Message has been deleted

Frank P. Westlake

unread,
Nov 17, 2009, 5:48:24 PM11/17/09
to
"carlos"
news:840db80e-0610-406b...@x31g2000yqx.googlegroups.com...
> Decimal to hex conversion in one line:
> set /a "DecValue=0x7D9"


Decimal conversion in 7+[3/11] of a line:

Set/A F=0xF&Echo This is the other 72+[8/11].

Frank


Timo Salmi

unread,
Nov 18, 2009, 5:50:52 AM11/18/09
to
Frank P. Westlake wrote:
> "Frank P. Westlake" news:hdudkf$rar$1...@news.albasani.net...
>> It looks like it could be very useful for changing number
>> bases. Here's

> The example I gave is a bad one because hex to decimal is more easily
> done with 'SET/A dec=0x%HEX%', but that is the only conversion it will
> do.

It also does octal do decimal:

33} How can I convert a binary, octal, hexadecimal into a decimal?
http://www.netikka.net/tsneti/info/tscmd033.htm

All the best, Timo

--
Prof. Timo Salmi mailto:t...@uwasa.fi ftp & http://garbo.uwasa.fi/
Hpage: http://www.uwasa.fi/laskentatoimi/english/personnel/salmitimo/
Department of Accounting and Finance, University of Vaasa, Finland
Useful CMD script tricks http://www.netikka.net/tsneti/info/tscmd.htm

Spacenet Wang

unread,
Nov 19, 2009, 9:41:55 PM11/19/09
to
foxidrive's method cannot parse the string containing wide character
(double bytes).

On Nov 17, 10:24 pm, Tom Lavedas <tglba...@cox.net> wrote:
> For some reason google won't let me add a reply to this thread (too
> old?):
>
> http://groups.google.com/group/alt.msdos.batch.nt/browse_frm/thread/f....

Frank P. Westlake

unread,
Nov 20, 2009, 4:25:44 AM11/20/09
to
"Spacenet Wang"
news:6c4cae05-b07f-4605...@2g2000prl.googlegroups.com...

This message was on Google but not on Albasani.

> foxidrive's method cannot parse the string containing
> wide character (double bytes).

True. But then the question would be whether you want string length or
character count. Normally what is needed is the display length, not the
physical length (string length). And with Unicode the display length is
not always equal to the Unicode character count (some are combined).

How do you handle Unicode strings in an environment variable? The zero
byte in the first 255 Unicode values (Unicoded ASCII) always terminate
the string. Do you just avoid these characters? But the space character
is very common and it contains a zero. I guess it could be replaced with
one of the other Unicode spaces.


Frank


Matt Williamson

unread,
Dec 29, 2009, 4:47:48 PM12/29/09
to

I created a couple of routines from this. The first is just a standard
StrLen function. The second is an InStr function that will return
multiple occurrences of string pos. I'd prefer to make InStr recursive
but this is what I came up with first.

@echo off
setlocal

call :InStr 0 "The Skinny Fox Jumped Out The Window" "n" out
echo %out%

call :StrLen "The Skinny Fox" out
echo %out%
endlocal&goto :eof

:StrLen
setlocal


for /f %%l in ('cmd/u/cecho/"%~1"^|find /v /c ""'
) do set /a CNT=%%l-5

endlocal&set %2=%cnt%&goto :eof

:InStr
setlocal enabledelayedexpansion
set pos=%1


for /f "delims=[]" %%l in (

'cmd/u/cecho/"%~2"^|find /n "%~3"'
) do (set /a pos=%%l-1
set/a c+=1&set pos!c!=!pos!
)
for /l %%a in (1,1,%c%) do (
call set p=!p! %%pos%%a%%
)
set p=%p:~1%
endlocal&set %4=%p%&goto :eof

-Matt

0 new messages