0

テキスト ファイル内の重複行をチェックし、それらの重複行を削除する便利な小さなツールが必要なだけです。したがって、ファイルに次のように記載されている場合:

A
B
C
D
A
E

次のようになります。

A
B
C
D
E

素敵でシンプル。しかし、テキスト ファイルは大きく、長いファイルの場所でいっぱいになるため、ファイルが 1 つ以上存在しないようにする必要があります。複製が 1 つだけ残っている限り、どの複製が削除されてもかまいません。だから私は次のようなもので大丈夫です:

B
C
D
A
E

これが私がこれまでに持っているすべてです:

@echo off
SetLocal EnableDelayedExpansion
set v=0
FOR /F "usebackq delims=" %%a in ("SomeArray.txt") do (
set /a var+=1
set var!v!=%%a
)
pause

可能なすべての重複をテストするためのループの作成をどこから始めればよいかわかりません。

4

2 に答える 2

1

行を「配列」に格納するコードが壊れています。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 のソリューションが一般的に適用可能な最善のアプローチだと思います。

  • CALL を使用すると、パフォーマンスが大幅に低下します (大きなファイルで顕著です)。

  • で始まる行;はスキップされます

  • & | < > ^問題を引き起こすような特殊文字

  • スクリプトは、スペースで区切られたトークンが 1 つしかないことを前提としています

欠点は簡単に修正できます。

@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 文字に制限されています。

また、上記のすべてのソリューションは空行を取り除きます。

于 2013-02-23T14:31:32.673 に答える
1

次の内容で cmd ファイル uniqeline.cmd を作成します。

@echo off
set prev=
for /f %%a in ('sort %1') do call :oneline %%a
goto :eof

:oneline
if NOT !%1!==!%prev%! echo %1
set prev=%1
goto :eof

コマンドラインから呼び出します:

uniqeline yourfilewithfilesnames.lst
于 2013-02-22T21:33:32.597 に答える