0

我只需要一个方便的小工具来检查文本文件中的重复行,它会删除那些重复的。所以如果文件说:

A
B
C
D
A
E

它会变成:

A
B
C
D
E

很好很简单。但是文本文件将很大并且充满长文件位置,我需要确保任何文件都不超过一个。只要只剩下一个,删除哪个重复项都没有关系。所以我会接受这样的事情:

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"
  )
)

上述解决方案有两个主要限制。

  • 重复比较不区分大小写,因为变量名不区分大小写。

  • 该解决方案将无法正确检测包含=因为=不能包含在变量名中的重复项。


我相信 rene 使用 SORT 的解决方案是最好的普遍适用的方法,虽然 rene 的代码有以下缺点

  • 使用 CALL 会显着降低性能(对于大文件很明显)

  • 以 开头的行;被跳过

  • 特殊字符如& | < > ^导致问题

  • 该脚本假定只有一个空格分隔的标记

缺点很容易解决:

@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 回答