【问题标题】:Batch Randomize Playlist Containing Percent Symbols包含百分比符号的批量随机播放列表
【发布时间】:2016-08-17 20:13:53
【问题描述】:

我有以下代码(已确定来源),它很棒,但是当标题包含百分号时它会失败。我喜欢它不使用临时文件并允许我覆盖原始文件的事实。关于如何为百分比符号解决此问题的任何想法?

  REM Randomize the Onesies playlist
  REM Source: stackoverflow.com/questions/19393155
  REM DOES NOT PROPERLY CREATE PLAYLIST ENTRY FOR ALBUMS CONTAINING PERCENT SYMBOLS (but it's fast)

  for /f "delims=" %%a in (G:\Playlists\Onesies.m3u8) do call set "$$%%random%%=%%a"
  (for /f "tokens=1,* delims==" %%a in ('set $$') do echo(%%b)>G:\Playlists\Onesies.m3u8
  echo Playlist Onesies.m3u8 has been created in the folder G:\Playlists\
  echo.
  pause

【问题讨论】:

标签: batch-file


【解决方案1】:

有问题的部分是call set "$$%%random%%=%%a"。为了解释原因,让我们从头开始。

简单地使用set "$$%random%=%%a" 是行不通的,因为%random% 会在整个for /F 循环或更一般地说,整个代码块被解析时被扩展(读取),所以相同的值将是为每个循环迭代返回。 call 技巧与变量周围的双百分号一起引入了另一个解析阶段,因此当解析整个 for /F 循环时,call set "$$%%random%%=%%a" 被解释为 call set "$$%random%=%a",因为批处理文件中的每个 %% 都是解释为一个文字%。因此,random 变量尚未展开。

对于每次循环迭代,for /F 变量将替换为当前迭代值。 call 启动另一个解析阶段,如前所述,因此 %random% 在每次循环迭代时被一个单独的随机数替换。假设%a是abritrary string,则该行首先被解释为call set "$$%random%=arbitrary string",在第二个解析阶段之后它变成set "$$16384=arbitrary string",假设%random%返回数字16384。

现在让我们以包含百分号的%a 的另一个示例值为例,例如string with % sign:在第一个解析阶段之后,我们有call set "$$%random%=string with % sign";在第二个之后,我们得到类似set "$$32767=string with sign" 的信息。百分号在这里消失了,因为命令行解释器遇到一个不能与另一个配对的% 符号(它们之间应该有一个变量名,比如%random%),所以它只是忽略了那个字符。如果%a 包含两个% 符号,例如more % signs % here,则结果将是more here(很可能),因为SPACEsignsSPACE 位于一对% 符号之间,将被视为(未定义,因此为空)变量的名称。

为了解决这个问题,我们需要避免 %a 通过第二个解析阶段。这可以通过避免%%a 出现在call 命令行中来实现。


因此,为了克服脚本中% 符号的丢失,您需要将%%a 存储到一个临时变量中,并在call 命令行中执行相同的双% 扩展,就像您已经做的那样对于random:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set /A "index=0"
for /f "usebackq delims=" %%a in ("G:\Playlists\Onesies.m3u8") do (
    set "item=%%a"
    call set "$$%%random%%.%%index%%=%%item%%"
    set /A "index+=1"
)
> "G:\Playlists\Onesies.m3u8" (
    for /f "tokens=1,* delims==" %%a in ('set $$') do echo(%%b
)
echo Playlist "Onesies.m3u8" has been created in the folder "G:\Playlists\".
echo/

endlocal
pause

另一种方法是申请delayed expansion:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Toggling delayed expansion in the loop is necessary to not lose exclamation marks.
set /A "index=0"
for /f "usebackq delims=" %%a in ("G:\Playlists\Onesies.m3u8") do (
    setlocal EnableDelayedExpansion
    rem // This loop passes `random` over the `endlocal` barrier:
    for /f %%b in ("!random!.!index!") do (
        endlocal
        set "$$%%b=%%a"
    )
    set /A "index+=1"
)
> "G:\Playlists\Onesies.m3u8" (
    for /f "tokens=1,* delims==" %%a in ('set $$') do echo(%%b
)
echo Playlist "Onesies.m3u8" has been created in the folder "G:\Playlists\".
echo/

endlocal
pause

问题中的原始代码依赖于内置随机数变量random,它可能会返回重复值。这会导致读取文件的某些行丢失的问题。

为了解决这个问题,上述两种方法都具有一个称为index 的计数器,对于for /F 循环读取的每一行来说,它当然是唯一的。此计数器值附加到随机值,以便连接的总字符串是唯一的。因此,与原始脚本相反,读取文件的任何行都不会丢失。

【讨论】:

  • 谢谢,但您的代码不起作用。它提供单行输出(文本文件的最后一行)。我尝试了几种类似的方法,似乎调用语句对于获得全套输出至关重要。
  • 对不起,我回答得太快了!代码现在已修复。请注意,random 可能会返回重复值(也适用于您在问题中发布的原始代码),从而导致原始输入文件中的行丢失;一旦找到解决方案,我也会解决它。
  • 是的,你是对的。接得好。我没有注意到原件由于重复值而丢失了行。是的,您的代码现在适用于百分比符号。我期待着你更好的解决方案!
  • 我只是 fixed the scripts 这样重复的 random 值不会再导致行丢失。还请查看 this answer 到我链接的问题 above...
  • 效果很好。谢谢。相当聪明的答案。
猜你喜欢
  • 2023-01-23
  • 2011-10-31
  • 2023-01-19
  • 1970-01-01
  • 1970-01-01
  • 2023-03-18
  • 2022-06-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多