user4673238
user4673238

Reputation:

Get position of substring by match index in batch script

I want to find the position of a substring by match index. To be precise, say there are 6 matches in a string and I want the position of match number 4. Example:

set "myString=barbarbarfoobarfoobarbar"
set "myMatch=bar"
set myMatchIndex=4
... do stuff ...
echo Position is: %position%


Position is: 13

Upvotes: 1

Views: 456

Answers (1)

user4673238
user4673238

Reputation:

The following will produce the desired result.

Does not work with special characters such as (!) and ("), make sure to properly sanitize inputs.

:indexOf
setlocal ENABLEDELAYEDEXPANSION
set indexOf_StringPosition=0
set "indexOf_Var1=%~1"
set "indexOf_Var2=%~2"
set indexOf_Var3=%3

:indexOf_NoInitLabel
set indexOf_CurrentPosition=0
set "indexOf_StringTemp=!indexOf_Var1:*%indexOf_Var2%=!"
if "%indexOf_StringTemp%"=="%indexOf_Var1%" (
    set indexOf_StringPosition=-1
    goto :indexOf_BreakLabel
)
set "indexOf_StringTemp2=!indexOf_Var1:%indexOf_Var2%%indexOf_StringTemp%=!"
if "%indexOf_StringTemp2%"=="" (
    set /a indexOf_CurrentPosition+=1
    goto :indexOf_BreakLabel
)

:indexOf_LoopLabel
if "!indexOf_StringTemp2:~%indexOf_CurrentPosition%,1!"=="" (
    set /a indexOf_CurrentPosition+=1
    goto :indexOf_BreakLabel
)
set /a indexOf_CurrentPosition+=1
goto :indexOf_LoopLabel

:indexOf_BreakLabel
set /a indexOf_StringPosition+=%indexOf_CurrentPosition%
set /a indexOf_Var3-=1
set "indexOf_Var1=!indexOf_Var1:~%indexOf_CurrentPosition%!"
if "indexOf_Var1"=="" (
    goto :indexOf_EndLabel
)
if "%indexOf_Var3%"=="0" (
    goto :indexOf_EndLabel
)
goto :indexOf_NoInitLabel

:indexOf_EndLabel
(endlocal & set %4=%indexOf_StringPosition%)
goto :eof

indexOf can be called like so:

@echo off

set "myString=barbarbarfoobarfoobarbar"
set "myMatch=bar"
set myMatchIndex=4
call :indexOf "%myString%" "%myMatch%" %myMatchIndex% position
echo Position is: %position%
pause


rem Position is: 13


Important Note: The algorithm's index starts at 1. This means "b" is treated as 1, "a" is treated as 2, and so on. To start the index at 0, add the following after :indexOf_EndLabel:

if not %indexOf_StringPosition%==-1 set /a indexOf_StringPosition-=1

Upvotes: 2

Related Questions