CrunchyHotDogs
CrunchyHotDogs

Reputation: 67

How to use FINDSTR to find a string in value of a variable?

Is it possible to use FINDSTR with a variable instead of a file?

I've tried researching this but my knowledge on batch isn't good enough yet.

I've made most of my batch file work flawlessly for what I need, but I'm having trouble extracting part of a string variable into a new variable.

The original variable for example would be S02E12 - Charge!. I would like to extract 02 to ep_seas, 12 to ep_num, and Charge! to ep_name. I have it working right now if that's the exact pattern of names, but I've come across some files that are in this pattern: S02E124 - Charge #2!

Is there a way I can dynamically get the values I need regardless of their length?

My idea was to use FINDSTR to search between the S and the E, then between E and space   (or -), then between - and the end. I'm not sure how I would proceed with this though.

Does anyone have a solution I can look into or can someone provide an example?

setlocal DisableDelayedExpansion
set mkvmerge="C:/Program Files/MKVToolNix/mkvmerge.exe"
set "output_folder=%cd%\Muxing"
for /r %%a in (*.mkv) do (
    set fi=%%a
    set ep=%%~na
    call :merge
)
goto :eof

:merge
set ep_name=%ep:~9%
set ep_num=%ep:~4,2%
set ep_seas=%ep:~2,1%
call %mkvmerge% -o "%output_folder%\%ep%.mkv" --track-name "0:%ep_name%" --language 0:und --default-track 0:yes --track-name "1:[JAP]" --language 1:jpn --default-track 1:yes --track-name "2:[ENG]" --language 2:eng --default-track 2:yes --forced-track 2:yes "%fi%" --track-order 0:0,0:1,0:2 --title "Fate Zero - Episode %ep_num%"
goto :eof

Upvotes: 2

Views: 5367

Answers (1)

Mofi
Mofi

Reputation: 49086

You could use this code for your task:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "output_folder=%CD%\Muxing"
for /R %%I in (*.mkv) do (
    set "fi=%%I"
    set "ep=%%~nI"
    call :merge
)
goto :EOF

:merge
for /F "tokens=1,2* delims=ES- " %%A in ("%ep%") do (
    set "ep_seas=%%A"
    set "ep_num=%%B"
    set "ep_name=%%C"
)
"%ProgramFiles%\MKVToolNix\mkvmerge.exe" -o "%output_folder%\%ep%.mkv" --track-name "0:%ep_name%" --language 0:und --default-track 0:yes --track-name "1:[JAP]" --language 1:jpn --default-track 1:yes --track-name "2:[ENG]" --language 2:eng --default-track 2:yes --forced-track 2:yes "%fi%" --track-order 0:0,0:1,0:2 --title "Fate Zero - Episode %ep_num%"
goto :EOF

The command FOR /F as used here parses the string in double quotes which is the file name.

The option "tokens=1,2* delims=ES- " results in splitting up the file name strings S02E12 - Charge! and S02E124 - Charge #2! into 3 substrings using the 4 specified characters as delimiters.

  1. Token 1 is 02 for both file names assigned to specified loop variable A.
  2. Token 2 is 12 and 124 for the two file names assigned to next loop variable after A according to ASCII table which is B.
  3. Token 3 is everything after the delimiters after token 2 which is Charge! and Charge #2! for the two files assigned to next but one loop variable C.

You know now why loop variables are case-sensitive while environment variables are not case-sensitive. The specified loop variable defines which characters the next loop variables have on using for /F with more than one token/substring.

* appended to a token number X means rest of the string/line after the delimiters after substring X should be assigned to next loop variable without any further splitting on delimiters. So the string after S02E12 -  and S02E124 -  can contain also delimiter characters and is nevertheless assigned completely to loop variable C.

Please note that a string starting with E or S after hyphen and space is interpreted also as delimiter and therefore missing in string assigned to loop variable C. The FOR loop in subroutine merge could be replaced by following code to get a working solution for a file name like S03E48 - Extended Version.mkv.

for /F "tokens=1* delims=- " %%A in ("%ep%") do (
    set "ep_name=%%B"
    for /F "tokens=1,2 delims=ES" %%C in ("%%A") do (
        set "ep_seas=%%C"
        set "ep_num=%%D"
    )
)

The outer loop assigns S03E48 to loop variable A and Extended Version to loop variable B. The inner loop splits up S03E48 once again into 03 assigned to loop variable C and 48 assigned to loop variable D.

By the way: The directory separator on Windows is \ and not / as on Unix/Linux/Mac although Windows kernel functions support also file/directory paths with / with automatic correction to \.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • call /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • set /?
  • setlocal /?

One last note:

It is possible to use FINDSTR on an environment variable for example with:

echo %ep% | findstr /R "^S[0123456789][0123456789]"

But FINDSTR never outputs just the matching string. It always outputs the entire line containing the found string. So FINDSTR is of no help here for splitting the file name up into separate parts.

Upvotes: 3

Related Questions