如何批量检查大型文本文件中的重复项?

时间:2013-02-22 21:06:53

标签: batch-file

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

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

我不知道从哪里开始制作循环来测试所有可能的重复项。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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"
  )
)

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

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

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

我认为使用SORT的rene解决方案是最常用的方法,尽管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个字符。

此外,上述所有解决方案都会删除空行。