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

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つの追加の例を参照してください。1つ目は一時的に有効化された遅延拡張を再度使用し(Ansgarsの回答を参照)、2つ目はを使用し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"

バッチ処理をお楽しみください!マーティン

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

あなたが得るでしょう

スペシャル| <> 〜\²³{[]}€$%&/()=?chars.flac

それ以外の

スペシャル| <>〜\²³{[]}!"´'`üäö@;:€$%&/()=?chars.flac


編集:ステートメント内の変数が展開されるときの遅延展開制御。スクリプトの重要なステートメントは次の行です

set "line=%%a"

これは、ループ変数の値を変数に割り当て%%aますline%%a遅延拡張を無効にすると、スクリプトインタープリターは%%a解析時に拡張できないため、のリテラル値が割り当てられます。ただし、遅延展開を有効にすると、実行時にbang変数が展開されるため、インタープリターは、結果が変数に割り当てられる前に、の値を調べてその中の値を%%a展開します。!whatever!line

おそらく、例を挙げればもっと明確になるでしょう。行を追加する場合

%foo%!foo!

入力ファイルに移動し、スクリプトで変数を定義します。

@echo on & setlocal ENABLEEXTENSIONS

set "foo=bar"
set "InFile=%~1"
...

変数に割り当てられた後も拡張された後 set "line=%%a"も遅延拡張を有効にすると(インタープリターは実行時間前の値を認識しません)、次の出力が得られます。%foo%!foo!%%aline%%a

%foo%!foo!

インタプリタが結果を変数に割り当てる前にbang-variablesを展開する に遅延展開を有効にすると、次の出力が得られます。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評価されるため、変数には値が割り当てられます。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 に答える