3

I need help to split a file name or folder name into two parts.
All files in the subfolders use always the same naming convention:

mainfolder/artist - title/artist - title.ext

I started with creating a batch file which writes .nfo files (recursive) for video files. Everything is working fine, but I just can't find a way to echoing the part1 (artist) before delimiter  -  and after it to have part2 (title).

Here is what I have now:

@echo off
TITLE NFO creator Musicvideos
COLOR B
ECHO -------------------------------------------------------------------------
ECHO  Create NFO for Musicvideos, all existing will be overwritten
ECHO  Push key to Start
ECHO -------------------------------------------------------------------------
ECHO.
PAUSE > NUL
REM Ende Header
for /r %%a in (*.mkv *.avi *.mp4) do (
(
echo ^<?xml version="1.0" encoding="UTF-8" standalone="yes"?^>
echo ^<musicvideo^>
for %%b in ("%%~na") do echo ^  ^<title^>%%~b^</title^>
echo ^  ^<^!-- start test set attributes --^>
for %%b in ("%%~na") do echo ^  ^<path^>%~dp0^</path^>
for %%b in ("%%~na") do echo ^  ^<name^>%%~na^</name^>
for %%b in ("%%~na") do echo ^  ^<filenameandpath^>%%~a^</filenameandpath^>
for %%b in ("%%~na") do echo ^  ^<basepath^>%%~a^</basepath^>
for %%b in ("%%~na") do echo ^  ^<before^>^</before^>
REM for "tokens=1,2 delims= - " %%b  in ("%%~na") do (
REM echo ^  ^<before^>^%%a</before^>
REM echo ^  ^<after^>^%%b</after^>
REM )
REM test end
echo ^  ^<rating^>^0.000000^</rating^>
echo ^  ^<userrating^>^8^</userrating^>
echo ^  ^<epbookmark^>^0.000000^</epbookmark^>
echo ^  ^<year^>^</year^>
echo ^  ^<track^>^-1^</track^>
echo ^  ^<album^>^</album^>
echo ^  ^<artist^>^</artist^>
echo ^  ^<genre^>^</genre^> 
echo ^  ^<outline^>^</outline^>
echo ^  ^<plot^>^</plot^>
echo ^  ^<tagline^>^</tagline^>
echo ^  ^<thumb^>^</thumb^>
echo ^  ^<status^>^</status^>
echo ^  ^<studio^>^</studio^>
echo ^  ^<art^>
echo ^      ^<fanart^>%~dp0^%%~na^-fanart.jpg^</fanart^>
echo ^      ^<poster^>%~dp0^%%~na^-poster.jpg^</poster^>
echo ^      ^<artistthumb^>%~dp0^%%~na^-artistthumb.jpg^</artistthumb^>
echo ^      ^<banner^>%~dp0^%%~na^-banner.jpg^</banner^>
echo ^      ^<clearlogo^>%~dp0^%%~na^-clearlogo.png^</clearlogo^>
echo ^      ^<discart^>%~dp0^%%~na^-discart.png^</discart^>
echo ^      ^<landscape^>%~dp0^%%~na^-landscape.jpg^</landscape^>
echo ^  ^</art^>
echo ^</musicvideo^>
)>"%%~dpna.nfo"
)
ECHO.
ECHO Creatin is done
ECHO Push key to exit
ECHO.
PAUSE > NUL
Mofi
  • 46,139
  • 17
  • 80
  • 143
  • 1
    `for /f` delimiters are restricted to single characters, you may use string substitution via regular variables to replace multiple characters with a single distinct char first. –  Mar 04 '19 at 02:14
  • You're using `%~dp0` once in your script, which points to the parent directory of the batch script; note that this might not be the same as the current working directory (which is the one used by the `for /R` loop)... – aschipfl Mar 04 '19 at 14:08
  • @aschipfl : batch will always be in main folder, and its intented to run from there.Because it will write an nfo.file in each subdir for each "given" file As the file tree structure is very simple and will never change-> MainFolder (with batch)\Artist -Title Folder\\Artist - Title.fileext . There no more subfolder, – Marduk Leviatan Mar 05 '19 at 11:59
  • So to be safe, you should change your outer loop to: `for /R "%~dp0." %%a in (...) do (...)` (so there's no difference wheter you run the batch file from command prompt or by double-clicking its icon in Explorer) – aschipfl Mar 05 '19 at 12:09

4 Answers4

3

This is the way I would do it:

@echo off
setlocal
for /R %%A in (*.mkv *.avi *.mp4) do call :SplitFileName "%%~nA"
goto :EOF

:SplitFileName
set "FileName=%~1"
set "Title=%FileName: - =" & set "Artist=%"
echo Artist=%Artist%
echo Title=%Title%
exit /B

Further details at Split string with string as delimiter. Pay attention to the comment at such an answer...

Aacini
  • 65,180
  • 12
  • 72
  • 108
1

I cannot find a reason for all the loops for %%b in ("%%~na") do you are using, particularly because you are often not even using %%b in their bodies.

Anyway, splitting file names at a certain sub-string can be easily done by first replacing the sub-string by a single character that is forbidden in file names (like :, for example) and then using that character as a delimiter in a for /F loop:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Loop through all matching files recursively:
for /R %%a in (*.mkv *.avi *.mp4) do (
    rem // Store file name in variable:
    set "NAME=%%~na"
    rem /* Toggle delayed expansion to be able to write a variable
    rem    in the same block of code without losing `!`: */
    setlocal EnableDelayedExpansion
    rem // Remove everything before first occurrence of and including ` - `:
    echo Title:  !NAME:* - =!
    rem // Replace ` - ` by `:` and use the latter as delimiter:
    for /F "tokens=1 delims=: eol=:" %%b in ("!NAME: - =:!") do (
        endlocal
        echo Artist: %%b
    )
)

endlocal
exit /B

The above code assumes that both the artist and the title portions are not empty. The title part may include the sub-string - on its own.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • Thanks for response, i will test suggested method later. The main reason for for [%%b in ("%%~na") do] is to have lookup for file to get the ext. So its basically just needed for 2 wished tags in the xml which will be written. – Marduk Leviatan Mar 04 '19 at 10:53
  • Sorry, I can't follow... instead of using `for %%b in ("%%~na") do echo %%~b` you could simply use `echo %%~na` as it's exactly the same... if you're not using `%%~b` at all you can just remove the whole `for %%b` loop... – aschipfl Mar 04 '19 at 14:07
  • for %%b in ("%%~na") do echo %%~b will write the full path + filenameext.ext in the .nfo of each file in subfolder folder e.g. H:\-- test create nfo\A Band Of Buriers - Filth\A Band Of Buriers - Filth.mp4 But echo %%~na will result in just the foldername A Band Of Buriers - Filth – Marduk Leviatan Mar 05 '19 at 11:45
  • No, `%%~na` is the base name of the file with the extension removed, it's not the name of the parent folder; still you could do `echo %%~na` since wrapping around the `for %%b` loop doesn't change anything... – aschipfl Mar 05 '19 at 12:05
0

This is an example on how to split a file name on first hyphen character.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /R %%A in (*.mkv *.avi *.mp4) do (
    for /F "eol=| tokens=1* delims=-" %%B in ("%%~nA") do (
        set "Artist=%%B"
        set "Title=%%C"
        setlocal EnableDelayedExpansion
        if "!Artist:~-1!" == " " set "Artist=!Artist:~0,-1!"
        if defined Title if "!Title:~0,1!" == " " set "Title=!Title:~1!"
        echo Artist=!Artist!
        if defined Title (echo Title=!Title!) else echo %%~na has no title.
        endlocal
    )
)
endlocal

The outer FOR loop searches recursive in current directory and all subdirectories for non-hidden files with file extension mkv, avi or mp4 and assigns the full qualified file name (file path + file name + file extension) of a found file to loop variable A.

The inner FOR loop interprets just the file name without path and file extension as string to process.

The end of line character is redefined from default ; which can be at beginning of a file name to | which no file name can ever contain to avoid that a file name starting by chance with a semicolon is ignored by the inner FOR loop.

By default FOR with option /F processing a double quoted string splits up the string into substrings using normal space and horizontal tab as string delimiters and assigns just first space/tab separated string to the specified loop variable. This string splitting behavior is modified with tokens=1* delims=- to split the file name string on hyphens instead of spaces/tabs with ignoring hyphens at beginning of file name and assigning the string up to first hyphen inside the file name to specified loop variable B and everything after first (sequence of) hyphen(s) to next loop variable according to ASCII table without any further string splitting which is loop variable C.

In other words on a file name like Artist - title the string Artist  with a space at end is assigned to loop variable B and the string  title with a space at beginning is assigned to loop variable C. The two unwanted spaces need to be removed. This can be done using string substitution. But this must be done using delayed expansion not yet enabled because of file names containing an exclamation mark should be also processed correct. For that reason delayed environment variable expansion is next enabled inside the inner FOR loop.

The first IF condition checks if last character of artist string is really a space character and runs the string substitution to remove this space at end of artist string if this condition is true.

The second IF condition first checks if an environment variable Title is defined at all because of the commands of inner FOR loop are also executed on file name does not contain a hyphen at all in which case %%C expands to an empty string and so environment variable Title is deleted from list of environment variables.

The nested third IF condition checks if first character of value of defined environment variable Title is a space and runs the string substitution to redefine Title without first character if this condition is true.

Now artist and title strings can be output before delayed expansion is disabled again by restoring previous environment. Please read this answer for details about the commands SETLOCAL and ENDLOCAL and what exactly happens on each execution of SETLOCAL and ENDLOCAL because of there is much more done than just enabling and disabling delayed environment variable expansion on each found file name.

Note: The title part can contain also the character sequence space, hyphen, space as well as one or more hyphens, but of course the artist string should not contain a hyphen as this character is interpreted as separator between artist and title independent on spaces existing around the hyphen or not. Windows command processor is not designed for enhanced string manipulations like other script interpreters. A different code would be necessary if the condition for splitting file name in artist and title must be space, hyphen, space and not just hyphen.

Other batch file code using  -  to split file name into artist and title strings:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /R %%A in (*.mkv *.avi *.mp4) do call :ProcessFileName "%%~nA"
endlocal
goto :EOF

:ProcessFileName
set "FileName=%~1"
set "Title=%FileName:* - =%"
setlocal EnableDelayedExpansion
set "Artist=!FileName: - %Title%=!"
echo Artist=!Artist!
echo Title=!Title!
endlocal
goto :EOF

But this solution using just string substitutions in a subroutine does not work on title string containing an equal sign used as delimiter on string substitution. It is also much slower in comparison to above batch file solution on processing a large amount of file names.

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 /?
  • if /?
  • set /?
  • setlocal /?

See also Where does GOTO :EOF return to?

Mofi
  • 46,139
  • 17
  • 80
  • 143
0

Assuming your title always have only a single - splitting artist from title:

@echo off
setlocal enabledelayedexpansion

for /r %%a in (*.mkv *.avi *.mp4) do (
    set "fname=%%~na"
    set "fname=!fname: - =-!"
    for /f "tokens=1,2 delims=-" %%i in ("!fname!") do (
       echo The artist is %%i
       echo The title is %%j
       echo The extension is %%~xa
    )
)

We replace the space-space with a - and then delimit on it.

Gerhard
  • 22,678
  • 7
  • 27
  • 43