批量随机化包含百分比符号的播放列表

时间:2016-08-17 20:13:53

标签: batch-file

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

  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

1 个答案:

答案 0 :(得分:2)

有问题的部分是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%将被每个循环迭代的单个随机数替换。假设%aabritrary string,该行首先被解释为call set "$$%random%=arbitrary string",在第二个解析阶段之后变为set "$$16384=arbitrary string",假设%random%返回数字{ {1}}。

现在让我们为包含百分号的16384采用另一个示例值,例如%a:在第一个解析阶段之后,我们有string with % sign;在第二个之后,我们得到类似call set "$$%random%=string with % sign"的东西。百分号在此处消失,因为命令行解释器遇到一个set "$$32767=string with sign"符号,该符号无法与另一个符号配对(其间需要变量名称,如%),因此它只是解除那个角色。如果%random%包含两个%a符号,例如%,则结果为more % signs % here(最有可能),因为 SPACE {{ 1}} SPACE ,位于一对more here符号之间,将被视为(未定义,因此为空)变量的名称。

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

因此,要克服脚本中%%a符号的丢失,您需要将call存储到临时变量中,并在{{1}内进行相同的双%扩展像你已经为%%a做的命令行:

%

另一种方法是应用delayed expansion

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 的计数器为特色,当然对于@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 循环读取的每一行都是唯一的。此计数器值附加到随机值,以便总连接字符串是唯一的。因此,与原始脚本相反,读取文件的所有行都不会丢失。