Cmd和感叹号 - 第二部分

问题描述:

我真的好奇为什么我的字符串替换过程在解析包含任何特殊字符(包括感叹号)的文本文件时起作用。我预计延迟变量扩展将关闭符号,百分号等特殊的含义,但反而会失败感叹号...Cmd和感叹号 - 第二部分

代码:

@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年半,我不得不再次使用这个代码片断。请参阅另外两个处理有毒字符的示例。第一个使用临时启用延迟扩展(请参阅Ansgars答案),第二个使用CALL。两者都将解析当前目录中和下方的非空文件的路径和名称,但不会将驱动器盘符和路径拖尾到当前目录。

实施例#1(在set "File=!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 

文件和文件夹测试:

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%!" 

你会得到

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

,而不是

专题| <>〜\³³{[]}! “''üäö@;:€$%& /()=?chars。FLAC


编辑:延迟扩展控件时,在一份声明变量扩展。在脚本中的关键语句是线

set "line=%%a" 

其分配循环变量%%a给变量line值。在禁用延迟扩展的情况下,分配%%a的文字值,因为脚本解释器在解析时无法扩展%%a。但是,如果启用延迟扩展,则bang变量会在执行时展开,因此解释器将查看%%a的值并在将结果分配给变量line之前将其中的任何!whatever!展开。

也许它会变得更清晰的例子。如果你添加一条线

%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之前,所以你得到这个输出之前延迟扩展

%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"在当前上下文中,然后在call新的上下文,其中%foo%膨胀以bar,以及评估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 
) 
+0

你能解释一下如何通过启用延迟扩展来扩展行吗?当我在新的本地环境中指定%% a时,我不明白为什么字符串会被这样裁剪。谢谢!而且代码有点复杂,因为它只是一个脚本的剪辑,我需要它作为子例程。马丁 – CmdQuestion 2013-03-10 12:43:39

+0

干得好!非常感谢。马丁 – CmdQuestion 2013-03-10 14:33:30