Page 1 of 2

how can i get position of a character(s) in a string?

Posted: 31 Aug 2007 03:21
by hgulcan
how can i get position of a character(s) in a string?

let the string is "This is the example."

i want to get starting position of "the".

thanks.

Posted: 02 Sep 2007 01:24
by DosItHelp
hgulcan,

Below a findString function and how to use it.
The result of the example is: "Position is: 8"
To try it out copy both code blocks into a new batch file.

Code: Select all

@ECHO OFF

set "s=This is the example."
call:findString s "the" pos

if not defined pos echo.Substring not found&goto:eof
echo.Position is: %pos%

goto:eof

Code: Select all

:findString -- returns the zero based postion of one string in another string of maximum length of 1023 characters
::          -- %~1: in - varible name of a string to be serached
::          -- %~1: in - string to be found
::          -- %~3: out- return variable name, will be set to position or undefined if string not found
SETLOCAL ENABLEDELAYEDEXPANSION
set "str=!%~1!"
set "str=!str:%~2=@@@@!
set "str=%str:@@@@="&REM %
if "%str%"=="!%~1!" (
   ENDLOCAL&IF "%~3" NEQ "" SET "%~3="
   GOTO:EOF
)
set str=A!str!&  rem keep the A up front to ensures we get the length and not the upper bond
                 rem it also avoids trouble in case of empty string
set len=0
set /a n=1024
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
set /a n^>^>=1, len+=n
 if !str:~%len%!. == . set /a len-=n
( ENDLOCAL & REM RETURN VALUES
    IF "%~3" NEQ "" SET %~3=%len%
)
GOTO:EOF


DosItHelp? :wink:

Posted: 02 Sep 2007 14:46
by jeb
Hi,

nice trick to truncate the string.
But here is a little bit better version, that work also for (should work for all strings)
set "s=This@@@@ is the example."
call:findString s "the" pos


:findString -- returns the zero based postion of one string in another string of maximum length of 1023 characters
:: -- %~1: in - varible name of a string to be serached
:: -- %~2: in - string to be found
:: -- %~3: out- return variable name, will be set to position or undefined if string not found
SETLOCAL ENABLEDELAYEDEXPANSION
set "str=!%~1!"
REM set "str=!str:%~2=@@@@!
REM set "str=%str:@@@@="&REM %
set "str=!str:%~2="!
...

btw. Has the <&rem %> part in <set "str=%str:@@@@="&REM %>
a special meaning or is the line
<set "str=%str:@@@@="%> always equivalent? :?:

Posted: 07 Sep 2007 21:43
by DosItHelp
jeb,

- set "str=!%~1!"
str is now "This is the example"

- set "str=!str:%~2=@@@@!
str is now "This is @@@@ example"

- set "str=%str:@@@@="&REM %
this finally truncates the string, i.e. before executing it evaluates to:
set "str="This is "&REM example

so that str is now "This is ".

How does your example get rid of the stuff after "the"?

Posted: 07 Sep 2007 22:37
by DosItHelp
Speaking of "better"...

Code: Select all

:findString -- returns position of first occurrence of a string in another string, case sensitive, maximum string length is 1023 characters
::          -- %~1: in - varible name of a string to be searched
::          -- %~1: in - string to be found
::          -- %~3: out- return variable name, will be set to position or undefined if string not found
:$source http://www.dostips.com
SETLOCAL ENABLEDELAYEDEXPANSION
set "pos="
set "str=!%~1!"
for /L %%a in (0,1,1023) do (
   set "s=!str:~%%a!"
   if not defined pos if "%~2!s:*%~2=!"=="!s!" set "pos=%%a"
)
ENDLOCAL & IF "%~3" NEQ "" SET "%~3=%pos%"
GOTO:EOF


Code: Select all

:findStringNoCase -- returns position of first occurrence of a string in another string, NOT case sensitive, maximum string length is 1023 characters
::          -- %~1: in - varible name of a string to be searched
::          -- %~1: in - string to be found
::          -- %~3: out- return variable name, will be set to position or undefined if string not found
:$source http://www.dostips.com
SETLOCAL ENABLEDELAYEDEXPANSION
set "pos="
set "str=!%~1!"
for /L %%a in (0,1,1023) do (
   set "s=!str:~%%a!"
   if not defined pos if /i "%~2!s:*%~2=!"=="!s!" set "pos=%%a"
)
ENDLOCAL & IF "%~3" NEQ "" SET "%~3=%pos%"
GOTO:EOF


Code: Select all

:findStringFromEnd -- returns position of last occurrence of a string in another string, case sensitive, maximum string length is 1023 characters
::          -- %~1: in - varible name of a string to be searched
::          -- %~1: in - string to be found
::          -- %~3: out- return variable name, will be set to position or undefined if string not found
:$source http://www.dostips.com
SETLOCAL ENABLEDELAYEDEXPANSION
set "pos="
set "str=!%~1!"
for /L %%a in (0,1,1023) do (
   set "s=!str:~%%a!"
   if /i "%~2!s:*%~2=!"=="!s!" set "pos=%%a"
)
ENDLOCAL & IF "%~3" NEQ "" SET "%~3=%pos%"
GOTO:EOF


Code: Select all

:findStringFromEndNoCase -- returns position of last occurrence of a string in another string, NOT case sensitive, maximum string length is 1023 characters
::          -- %~1: in - varible name of a string to be searched
::          -- %~1: in - string to be found
::          -- %~3: out- return variable name, will be set to position or undefined if string not found
:$source http://www.dostips.com
SETLOCAL ENABLEDELAYEDEXPANSION
set "pos="
set "str=!%~1!"
for /L %%a in (0,1,1023) do (
   set "s=!str:~%%a!"
   if "%~2!s:*%~2=!"=="!s!" set "pos=%%a"
)
ENDLOCAL & IF "%~3" NEQ "" SET "%~3=%pos%"
GOTO:EOF



:wink:

Posted: 10 Sep 2007 02:34
by jeb
Hi all,

your Version

Code: Select all

set "str=!%~1!"               --  str is now "This is the example"
set "str=!str:%~2=@@@@!       -- str is now "This is @@@@ example"
set "str=%str:@@@@="&REM %    -- this finally truncates the string, i.e. before executing it evaluates to:
                              --   set "str="This is "&REM example


> so that str is now "This is ".

> How does your example get rid of the stuff after "the"?
My Variant simple expand to

Code: Select all

set "str=!str:%~2="!    -- expand to set "str=This is"example


All text after the second " will be ignored without any error.

I suppose your first solution with using of strlen is faster than the others
with "extreme searching", but dont tested it yet.

Posted: 12 Sep 2007 23:20
by DosItHelp
jeb,

Yes you are right the binary approach is much faster.

The problem with using <set "str=!str:%~2="!> is that the search string may occur multiple times, e.g. if %~2 expands to the letter h then:

Code: Select all

set "str=!str:%~2="!    -- expands to set "str=T"is is t"e example
which causes an error saying:
is was unexpected at this time.

When changing the example string from "This" to "That" to "That is the example" then:

Code: Select all

set "str=!str:%~2="!    -- expands to set "str=T"at is t"e example
which causes same error:
is was unexpected at this time.

I expected it would complain about at now, but no.
Very confusing isn't it?

Re: how can i get position of a character(s) in a string?

Posted: 31 May 2011 10:18
by Ed Dyreen
What is the trick @DosItHelp is using in this line:

set "str=%str:@@@@="&REM %

>>&REM %<< ?

and why do they prefer this

set "str=!str:%~2="!

over this ?

set "str=!str:%~2=!"

yes, I know a little about the parser, but in practice it's a lot of guessing for me.

Re: how can i get position of a character(s) in a string?

Posted: 31 May 2011 11:33
by orange_batch
Yeah, I honestly wonder about voodoo syntax like that myself. How the heck does it make any sense? lol

Re: how can i get position of a character(s) in a string?

Posted: 31 May 2011 12:27
by dbenham
orange_batch wrote:Yeah, I honestly wonder about voodoo syntax like that myself. How the heck does it make any sense? lol

DosItHelp is injecting a command into the string replacement processing.

----------

Have I solved all the issues? and is it worth all the code?

Code: Select all

@echo off
setlocal disableDelayedExpansion
set "str=This! &"@@@@^&"&" is the string with the multiple problems"
set "search=the"
setlocal enableDelayedExpansion
echo str=!str!
set "str=!str:"=""!"
set "cmd=set ^"str2=!str:%search%="&rem!"
echo cmd=!cmd!
setlocal disableDelayedExpansion
%cmd%
setlocal enableDelayedExpansion
set "result=!str2:""="!"
echo result=[!result!]

output:

Code: Select all

str=This! &"@@@@&"&" is the string with the multiple problems
cmd=set "str2=This! &""@@@@&""&"" is "&rem string with "&rem multiple problems
result=[This! &"@@@@&"&" is ]


Dave Benham

Addendum - Oops - should probably double up quotes in search string as well with one more search and replace.

Re: how can i get position of a character(s) in a string?

Posted: 31 May 2011 16:40
by Ed Dyreen
It will still take me time to figure out the exact workings, cause I need to be sure I understand it fully &so when to use it.

I am turning this forum upside down, cause it holds secrets no other sites mention.

Too bad I didn't discover Dostips in 2006. I've googled often enough for the words DOS, CMD &commandline help :(

Dave, thank u very much for your dedication in explaining things :P

Re: how can i get position of a character(s) in a string?

Posted: 31 May 2011 16:50
by Cleptography
Ed Dyreen wrote:I am turning this forum upside down, cause it holds secrets no other sites mention.

@Ed
What secrets do you speak of, like prizes at the bottom of a box of Captin Crunch?

Re: how can i get position of a character(s) in a string?

Posted: 31 May 2011 16:52
by Ed Dyreen
YES, I can't leave until I know EVERYTHING, I'm autistic :x

but they say it passes into other obsessions every 10 years or so.

Re: how can i get position of a character(s) in a string?

Posted: 31 May 2011 16:57
by Cleptography
Image

Re: how can i get position of a character(s) in a string?

Posted: 01 Jun 2011 15:44
by jeb
dbenham wrote:Have I solved all the issues? and is it worth all the code?

No :wink:

It fails even with doubling the quotes, the problem is now ^"
It seems to be a general problem if you leave the quotes in the text, you got also problems with the carets.

Code: Select all

set "str=This! &"@@@@^&"&" is^^"& the string with the multiple problems"

And using the %cmd%, you always got problems with <LF> and <CR>, the <CR> are removed, and <LF> breaks the parsing immediatly.

My last solution (delayed expansion with a quote) fails with multiple occurence of the search string.
Therefore I try a new way of splitting the rest with a FOR /F and <LF> combination.

Code: Select all

@echo off
setlocal
for /f %%a in ('copy /Z "%~dpf0" nul') do set "CR=%%a"
set LF=^


rem TWO Empty lines are neccessary
set "str=This! &"@@@@^&"&" is^^"& the string with the multiple problems"
call :strip str "the"
setlocal EnableDelayedExpansion

goto :eof

:strip
setlocal EnableDelayedExpansion
set "var=!%~1!"
echo  input=!var!
REM *** Here is the trick, we replace the SEARCH-Text with a <LF>
REM *** Later the <LF> breaks the FOR /F loop
for %%a in ("!LF!") do set "var=!var:%~2=%%~a!"

for /F "tokens=* delims=" %%1 in ("!var!") DO (
   set "result=%%1"
   goto :leaveLoop
)
:leaveLoop
echo result=!result!

goto :eof


To preserve the carets and exclamation marks you could use it with the "secure return" technic.

jeb