我有以下代码(源标识),这很好,但是当标题包含百分比符号时它会失败。我喜欢它不使用临时文件并允许我覆盖原始文件的事实。有关如何解决百分比符号问题的想法吗?
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
答案 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%
将被每个循环迭代的单个随机数替换。假设%a
为abritrary 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
循环读取的每一行都是唯一的。此计数器值附加到随机值,以便总连接字符串是唯一的。因此,与原始脚本相反,读取文件的所有行都不会丢失。