【问题标题】:How to split filename by delimiter " - " and echoing the part before and after?如何通过分隔符“ - ”拆分文件名并在前后回显部分?
【发布时间】:2019-03-04 01:33:41
【问题描述】:

我需要帮助将文件名或文件夹名分成两部分。
子文件夹中的所有文件始终使用相同的命名约定:

主文件夹/艺术家 - 标题/艺术家 - 标题.ext

我首先创建了一个批处理文件,它为视频文件写入.nfo 文件(递归)。一切正常,但我只是找不到在分隔符  -  之前和之后回显 part1(艺术家) 以具有 part2(标题) 的方法。

这是我现在拥有的:

@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

【问题讨论】:

  • for /f 分隔符仅限于单个字符,您可以通过常规变量使用字符串替换,首先将多个字符替换为单个不同的字符。
  • 您在脚本中使用了一次%~dp0,它指向批处理脚本的父目录;请注意,这可能与当前工作目录(for /R 循环使用的目录)不同...
  • @aschipfl :批处理将始终位于主文件夹中,并且打算从那里运行。因为它会在每个“给定”文件的每个子目录中写入一个 nfo.file 因为文件树结构是非常简单,永远不会改变-> MainFolder (with batch)\Artist -Title Folder\\Artist - Title.fileext 。没有更多的子文件夹,
  • 为了安全起见,您应该将外部循环更改为:for /R "%~dp0." %%a in (...) do (...)(因此无论您是从命令提示符运行批处理文件还是通过在资源管理器中双击其图标来运行批处理文件都没有区别)跨度>

标签: batch-file split


【解决方案1】:

我会这样做:

@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

更多详情请访问Split string with string as delimiter。在这样的回答中注意评论...

【讨论】:

    【解决方案2】:

    我找不到您使用的所有循环 for %%b in ("%%~na") do 的原因,特别是因为您通常甚至没有在其体内使用 %%b

    无论如何,通过首先将子字符串替换为文件名中禁止的单个字符(例如:),然后使用该字符作为for /F 循环中的分隔符:

    @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
    

    上面的代码假定艺术家和标题部分都不为空。标题部分可以单独包含子字符串-

    【讨论】:

    • 感谢您的回复,我稍后会测试建议的方法。 [%%b in ("%%~na") do] 的主要原因是查找文件以获取分机。所以它基本上只需要在 xml 中写入 2 个希望的标签。
    • 对不起,我无法关注...而不是使用for %%b in ("%%~na") do echo %%~b,您可以简单地使用echo %%~na,因为它完全相同...如果您根本不使用%%~b您可以删除整个 for %%b 循环...
    • for %%b in ("%%~na") do echo %%~b 将在子文件夹中每个文件的 .nfo 中写入完整路径 + filenameext.ext,例如H:\-- test create nfo\A Band Of Buriers - Filth\A Band Of Buriers - Filth.mp4 但是 echo %%~na 只会产生文件夹名称 A Band Of Buriers - 污秽
    • 不,%%~na 是删除扩展名的文件的基本名称,它不是父文件夹的名称;你仍然可以做echo %%~na,因为环绕for %%b 循环不会改变任何东西......
    【解决方案3】:

    这是一个关于如何在第一个连字符上拆分文件名的示例。

    @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
    

    外部FOR循环在当前目录和所有子目录中递归搜索文件扩展名为mkvavimp4的非隐藏文件,并分配完整的限定文件名(文件找到的文件的路径+文件名+文件扩展名)循环变量A

    内部 FOR 循环仅将不带路径和文件扩展名的文件名解释为要处理的字符串。

    行尾字符从默认的;重新定义,它可以在文件名的开头到|,没有文件名可以包含以避免偶然以分号开头的文件名被忽略内部 FOR 循环。

    默认情况下 FOR 带有选项 /F 处理双引号字符串将字符串拆分为子字符串,使用普通空格和水平制表符作为字符串分隔符,并将第一个空格/制表符分隔的字符串分配给指定的循环变量。使用tokens=1* delims=- 修改此字符串拆分行为以在连字符而不是空格/制表符上拆分文件名字符串,并忽略文件名开头的连字符并将字符串分配给文件名内的第一个连字符到指定的循环变量B以及根据ASCII table的第一个(序列)连字符到下一个循环变量之后的所有内容,没有任何进一步的字符串拆分,即循环变量C

    换句话说,对于像Artist - title 这样的文件名,末尾带有空格的字符串Artist  分配给循环变量B,开头带有空格的字符串 title 分配给循环变量@987654340 @。需要删除两个不需要的空格。这可以使用字符串替换来完成。但这必须使用尚未启用的delayed expansion 来完成,因为包含感叹号的文件名也应该被正确处理。出于这个原因,下一个在内部 FOR 循环中启用延迟的环境变量扩展。

    第一个 IF 条件检查艺术家字符串的最后一个字符是否真的是空格字符,如果条件为真,则运行字符串替换以删除艺术家字符串末尾的空格。

    第二个IF条件首先检查是否定义了环境变量Title,因为内部FOR循环的命令也对文件名不执行完全包含连字符,在这种情况下 %%C 扩展为空字符串,因此环境变量 Title 将从环境变量列表中删除。

    嵌套的第三个 IF 条件检查定义的环境变量 Title 的值的第一个字符是否为空格,如果此条件为真,则运行字符串替换以重新定义不带第一个字符的 Title

    现在可以在通过恢复以前的环境再次禁用延迟扩展之前输出艺术家和标题字符串。请阅读 this answer 了解有关命令 SETLOCALENDLOCAL 的详细信息以及每次执行 SETLOCALENDLOCAL 会发生什么strong> 因为除了在每个找到的文件名上启用和禁用延迟的环境变量扩展之外,还有更多工作要做。

    注意: 标题部分还可以包含字符序列空格、连字符、空格以及一个或多个连字符,但当然艺术家字符串不应包含连字符,因为该字符被解释作为艺术家和标题之间的分隔符,独立于连字符周围是否存在空格。 Windows command 处理器不像其他脚本解释器那样设计用于增强字符串操作。如果艺术家和标题中分割文件名的条件必须是空格、连字符、空格而不仅仅是连字符,则需要使用不同的代码。

    其他使用 - 将文件名拆分为艺术家和标题字符串的批处理文件代码:

    @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
    

    但是这种在子例程中仅使用字符串替换的解决方案不适用于包含用作字符串替换分隔符的等号的标题字符串。在处理大量文件名时,与上述批处理文件解决方案相比,它也慢得多。

    要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

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

    另见Where does GOTO :EOF return to?

    【讨论】:

      【解决方案4】:

      假设您的标题始终只有一个 - 从标题中拆分艺术家:

      @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
          )
      )
      

      我们将space-space 替换为-,然后对其进行定界。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-04
        • 2020-01-15
        • 1970-01-01
        • 2022-12-25
        • 2021-06-14
        相关资源
        最近更新 更多