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

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
hgulcan
Posts: 1
Joined: 31 Aug 2007 03:17

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

#1 Post by hgulcan » 31 Aug 2007 03:21

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.

DosItHelp
Expert
Posts: 239
Joined: 18 Feb 2006 19:54

#2 Post by DosItHelp » 02 Sep 2007 01:24

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:

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

#3 Post by jeb » 02 Sep 2007 14:46

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

DosItHelp
Expert
Posts: 239
Joined: 18 Feb 2006 19:54

#4 Post by DosItHelp » 07 Sep 2007 21:43

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"?

DosItHelp
Expert
Posts: 239
Joined: 18 Feb 2006 19:54

#5 Post by DosItHelp » 07 Sep 2007 22:37

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:

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

#6 Post by jeb » 10 Sep 2007 02:34

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.

DosItHelp
Expert
Posts: 239
Joined: 18 Feb 2006 19:54

#7 Post by DosItHelp » 12 Sep 2007 23:20

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?

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

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

#8 Post by Ed Dyreen » 31 May 2011 10:18

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.

orange_batch
Expert
Posts: 442
Joined: 01 Aug 2010 17:13
Location: Canadian Pacific
Contact:

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

#9 Post by orange_batch » 31 May 2011 11:33

Yeah, I honestly wonder about voodoo syntax like that myself. How the heck does it make any sense? lol

dbenham
Expert
Posts: 2461
Joined: 12 Feb 2011 21:02
Location: United States (east coast)

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

#10 Post by dbenham » 31 May 2011 12:27

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.
Last edited by dbenham on 31 May 2011 17:10, edited 1 time in total.

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

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

#11 Post by Ed Dyreen » 31 May 2011 16:40

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

Cleptography
Posts: 287
Joined: 16 Mar 2011 19:17
Location: scriptingpros.com
Contact:

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

#12 Post by Cleptography » 31 May 2011 16:50

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?

Ed Dyreen
Expert
Posts: 1569
Joined: 16 May 2011 08:21
Location: Flanders(Belgium)
Contact:

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

#13 Post by Ed Dyreen » 31 May 2011 16:52

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.

Cleptography
Posts: 287
Joined: 16 Mar 2011 19:17
Location: scriptingpros.com
Contact:

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

#14 Post by Cleptography » 31 May 2011 16:57

Image

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

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

#15 Post by jeb » 01 Jun 2011 15:44

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

Post Reply