行を「配列」に格納するコードが壊れています。v
の代わりにインクリメントする必要がありますvar
。
重複をチェックするコードは単純ですが、時間がかかります。既存の値をループして、現在の行と一致するかどうかを確認します。一致が見つからない場合にのみ、現在の行をエコーして保存します。一意の行の数が多いほど、遅くなります。
以下のスクリプトは、ファイルの名前を最初で唯一のパラメーターとして想定しています。
@echo off
setlocal enableDelayedExpansion
set n=0
for /f "usebackq delims=" %%A in (%1) do (
set "skip="
for /l %%N in (1 1 !n!) do if "%%A"=="!var%%N!" set skip=1
if not defined skip (
echo %%A
set /a n+=1
set "var!n!=%%A"
)
)
;
デフォルトの FOR /F EOL オプションは で始まる行をスキップするため、行が で始まる場合、上記は失敗します;
。これは、EOL と DELIMS の両方を何も設定しない厄介な構文で修正できます。usebackq^ delims^=^ eol^=
!
FOR /F 変数が展開されると、遅延展開によって行の値が破損するため、行に次のものが含まれている場合、上記も失敗します。これは、必要に応じて遅延拡張を慎重に有効または無効にすることで修正できます。
@echo off
setlocal disableDelayedExpansion
set n=0
for /f usebackq^ delims^=^ eol^= %%A in (%1) do (
set "ln=%%A"
set "skip="
setlocal enableDelayedExpansion
for /l %%N in (1 1 !n!) do if "!ln!"=="!var%%N!" set skip=1
if defined skip (endlocal) else (
echo !ln!
set /a n+=1
for %%N in (!n!) do (
endlocal
set "var%%N=%%A"
set "n=%%N"
)
)
)
しかし、はるかに高速でシンプルなソリューションがあります。
可能な限り迅速かつ簡単な純粋なバッチ ソリューションは、行の内容を変数の名前に組み込むことです。重複を確認するには、変数が既に定義されているかどうかを確認します。
@echo off
setlocal
:: clear existing _ variables
for /f "eol== delims==" %%V in ('set _ 2^>nul') do set "%%V="
:: read and echo file, throw away duplicates (case insensitive)
:: does not work if line contains =
for /f usebackq^ delims^=^ eol^= %%A in (%1) do (
if not defined _%%A (
echo %%A
set "_%%A=1"
)
)
上記のソリューションには 2 つの大きな制限があります。
rene のコードには次の欠点がありますが、SORT を使用した rene のソリューションが一般的に適用可能な最善のアプローチだと思います。
欠点は簡単に修正できます。
@echo off
setlocal disableDelayedExpansion
set "old="
for /f delims^=^ eol^= %%A in ('sort %1') do (
set "new=%%A"
setlocal enableDelayedExpansion
if "!new!" equ "!old!" (endlocal) else (
echo !new!
endlocal
set "old=%%A"
)
)
すべてのバッチ ソリューションは、行の最大長が ~8191 文字に制限されています。
また、上記のすべてのソリューションは空行を取り除きます。