3

我真的很想知道为什么我的字符串替换过程在解析包含任何特殊字符(包括感叹号)的文本文件时有效。我预计延迟变量扩展会关闭&符号,百分号等的特殊含义,但会因感叹号而失败......

代码:

@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

输入文件.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"

输出文件.txt:

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

编辑/补充:

1 1/2 年后,我不得不再次使用此代码段。请参阅另外两个处理毒字符的示例。第一个使用临时启用延迟扩展(参见 Ansgars 答案),第二个使用CALL. 两者都将解析当前目录中和当前目录下非空文件的路径和名称,但没有尾随驱动器号和当前目录的路径。

示例#1(不需要在set "File=!File..."and中加上双引号):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

用于测试的文件和文件夹:

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"

享受批处理!马丁

4

1 回答 1

7

那是因为您启用延迟扩展 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%!"

你会得到

特别 | < > ~ \ ²³ { [ ] } € $ % & / ( ) = ? 字符.flac

代替

特别 | < > ~ \ ²³ { [ ] } !" ´ ' ` üäö @ ; : € $ % & / ( ) = ? chars.flac


编辑:延迟扩展控制语句中的变量何时扩展。脚本中的关键语句是该行

set "line=%%a"

它将循环变量的值分配给%%a变量line。禁用延迟扩展后,将分配 的文字值%%a,因为脚本解释器无法%%a在解析时扩展。但是,当您启用延迟扩展时,bang-variables 会在执行时扩展,因此解释器会在将结果分配给 variable 之前查看%%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!

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

%foo% 酒吧

%foo%只会在解析时扩展,此时解释器看不到 的实际值%%a,因此在这里%foo%仍然是文字%foo%

进一步的赋值,如set "line=!line:.wav=%NewExtension%!"不影响变量内的刘海或百分号,因为扩展不是传递的,即它转换!line!%foo% bar(or %foo% !foo!) 然后停止。

call不过,您可以使用该命令强制扩展变量内的(百分比)变量。一个命令call set "line=!line!"首先call set "line=%foo% bar"在当前上下文中扩展为,然后在一个新的上下文中call进行评估,其中也扩展为,因此变量被赋值。set "line=%foo% bar"%foo%barlinebar 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
)
于 2013-03-10T12:16:11.397 回答