Cmd和感叹号 – 第二部分

我真的想知道为什么我的stringreplace过程parsing包含任何特殊字符(包括感叹号)的文本文件时工作。 我期望延迟variables扩展将closures&符号,百分号等的特殊含义,但将失败,而不是感叹号…

码:

@echo on & setlocal ENABLEEXTENSIONS set "InFile=%~1" set "OutFile=%~2" set "Replace=%~3" CALL :ParseCue "%%InFile%%" "%%OutFile%%" "%%Replace%%" endlocal &GOTO:EOF :ParseCue @echo on & setlocal ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION set "FileToParse=%~1" set "OutputFile=%~2" set "NewExtension=%~3" for /F "usebackq tokens=* delims=" %%a in ("%FileToParse%") DO ( set "line=%%a" @echo on & setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION set "line=!line:.wav=%NewExtension%!" echo(!line!>>"%OutputFile%" endlocal ) endlocal &GOTO:EOF 

InputFile.txt:

 This a test for parsing lines with special characters Rock & Roll.wav Rock & Roll!.wav Special | < > ~ \ ²³ { [ ] } ! " ´ ' ` üäö @ ; : € $ % & / ( ) = ? chars.wav 

命令行语法:

 D:\Users\Public\Batch\YAET>parse.bat "InputFile.txt" "OutputFile.txt" ".flac" 

OutputFile.txt:

 This a test for parsing lines with special characters Rock & Roll.flac Rock & Roll!.flac Special | < > ~ \ ²³ { [ ] } ! " ´ ' ` üäö @ ; : € $ % & / ( ) = ? chars.flac 

编辑/补充:

1/2年后,我不得不再次使用这段代码。 看另外两个处理有毒字符的例子。 第一个使用临时启用延迟扩展(见Ansgars答案),第二个使用CALL 。 两者都将parsing当前目录中和下面的非空文件的path和名称,但不会将驱动器号和path拖尾到当前目录。

例子#1(在set "File=!File..."echo "!FILE!">>...双引号echo "!FILE!">>...是不需要的):

 @echo off & setlocal ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION del NonEmptyFiles.txt >NUL 2>&1 echo Searching non-empty files in and below current directory ... for /f "tokens=*" %%I in ('dir /s /b /a:-D') do ( if not %%~zI==0 ( set "File=%%I" setlocal ENABLEDELAYEDEXPANSION set "File=!File:%cd%\=!" echo "!File!">> NonEmptyFiles.txt endlocal ) ) echo Done. See NonEmptyFiles.txt. endlocal &goto:EOF 

示例#2(较慢,需要包含双引号):

 @echo off & setlocal ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION del NonEmptyFiles.txt >NUL 2>&1 echo Searching non-empty files in and below current directory ... for /f "tokens=*" %%i in ('dir /s /b /a:-D') do ( if not %%~zi==0 ( set "File=%%i" call set "File=%%File:%cd%\=%%" call echo "%%File%%">> NonEmptyFiles.txt ) ) echo Done. See NonEmptyFiles.txt. endlocal &goto:EOF 

用于testing的文件和文件夹:

 D:\Martin\Any & Path>dir /s /b /a:-D D:\Martin\Any & Path\Hello! World!.txt D:\Martin\Any & Path\Rock & Roll\!File! !!File!!.txt D:\Martin\Any & Path\Rock & Roll\%File% %%File%% %%I.txt D:\Martin\Any & Path\Rock & Roll\Poison! !§$%&()=`´'_;,.-#+´^ßöäüÖÄÜ°^^#.txt D:\Martin\Any & Path\Rock & Roll\SizeZero.txt 

输出:

 D:\Martin\Any & Path>stringinforloop.bat Searching non-empty files in and below current directory ... See NonEmptyFiles.txt. Done. D:\Martin\Any & Path>type NonEmptyFiles.txt "Hello! World!.txt" "Rock & Roll\!File! !!File!!.txt" "Rock & Roll\%File% %%File%% %%I.txt" "Rock & Roll\Poison! !§$%&()=`´'_;,.-#+´^ßöäüÖÄÜ°^^#.txt" 

享受配料! 马丁

那是因为你 set "line=%%a" 之后启用了延迟扩展:

 set "line=%%a" @echo on & setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION set "line=!line:.wav=%NewExtension%!" 

如果您分配%%a 之前启用延迟扩展:

 @echo on & setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION set "line=%%a" set "line=!line:.wav=%NewExtension%!" 

你会得到

特殊| <>〜\³³{[]}€$%&/()=? chars.flac

代替

特殊| <>〜\³³{[]}! “''üäö@;:€$%&/()=?chars.flac


编辑:扩展语句中的变量时,延迟扩展控件。 在你的脚本中的关键陈述是线

 set "line=%%a" 

它将循环变量%%a的值赋给变量line 。 在禁用延迟扩展%%a会分配%%a的文字值,因为脚本解释器在解析时无法展开%%a 。 但是,当启用延迟扩展时,bang变量会在执行时被扩展,所以解释器会查看%%a的值并扩展任何!whatever! 在结果被分配给变量line

也许这个例子会变得更清晰。 如果你添加一行

%foo%!foo!

到输入文件并在脚本中定义变量:

 @echo on & setlocal ENABLEEXTENSIONS set "foo=bar" set "InFile=%~1" ... 

set "line=%%a" 之后启用延迟扩展时既不是%foo%也不是!foo! 在将%%a分配给变量line之前展开(解释器在执行时间之前没有看到%%a的值),所以你得到这个输出:

%foo%!foo!

set "line=%%a" 之前启用延迟扩展时,解释器会在将结果分配给变量line之前展开bang变量,因此您将得到以下输出:

%foo%吧

%foo%只会在解析时被扩展,此时解释器无法看到%%a的实际值,所以%foo%在这里仍然是%foo%

进一步分配,如set "line=!line:.wav=%NewExtension%!" 不要影响变量中的刘海或百分号,因为扩展不是可传递的,也就是说它翻译!line!%foo% bar (或%foo% !foo! )然后停止。

不过,您可以使用call命令强制变量内的(百分号)变量的扩展。 一个命令call set "line=!line!" 首先扩展到在当前上下文中call set "line=%foo% bar" ,然后在%foo%扩展为bar的新上下文中call评估set "line=%foo% bar" ,因此变量line被分配值bar bar


正如旁注:你的代码太复杂了。 你会得到完全相同的结果:

 set "FileToParse=%~1" set "OutputFile=%~2" set "NewExtension=%~3" for /F "usebackq tokens=* delims=" %%a in ("%FileToParse%") DO ( set "line=%%a" @setlocal ENABLEDELAYEDEXPANSION set "line=!line:.wav=%NewExtension%!" echo(!line!>>"%OutputFile%" endlocal )