如何使用批处理脚本或vb脚本从文本文件中删除重复的条目?

时间:2016-04-05 11:07:09

标签: batch-file vbscript

如何使用批处理脚本从文本文件中删除重复条目。我只想在“=”符号之前删除重复项,并且每个文本文件中都存在“%%”。文本文件看起来像下面

nvarchar

我有大约30个不同的文本文件,其中包含上述类型的条目,并希望删除重复的行并希望保留第一次出现。请记住,只有在“=”符号之前才能识别重复行,并且需要删除整行。每个不同的文本文件都有“%%”符号。如果有办法通过批处理脚本 vbscript ,请指导我?感谢

2 个答案:

答案 0 :(得分:0)

您可以将文件读入Excel而不将其拆分为多个列。使用Excel功能消除重复并将其保存回来。你可以在VBScript中完成所有这些。

Create an Excel Object
Loop
    Load text file
    Remove duplicates
    Save text file
Until there are no more files
Dispose of the Excel Object

单个作品的代码应该可以在网上轻松获得。请询问您可能需要的任何其他具体指示。

答案 1 :(得分:0)

这是一个简单的解决方案;让我们调用脚本rem-dups.bat。假设输入文件为test.txt且输出文件为result.txt,则需要将这些文件作为命令行参数提供,因此需要通过以下方式调用它:rem-dups.bat "test.txt" "results.txt"。这是脚本:

@echo off
setlocal EnableExtensions EnableDelayedExpansion

set "INFILE=%~1"
set "OUTFILE=%~2"
if not defined INFILE exit /B 1
if not defined OUTFILE set "OUTFILE=con"

for /F "usebackq tokens=1,* delims==" %%K in ("%INFILE%") do (
    set "LEFT=%%K"
    set "RIGHT=%%L"
    set "LEFT=!LEFT:*%%%%=__!"
    rem Remove `if` query to keep last occurrence:
    if not defined !LEFT! set "!LEFT!=!RIGHT!"
)
> "%OUTFILE%" (
    for /F "delims=" %%F in ('set __') do (
        set "LINE=%%F"
        echo(!LINE:*__=%%%%!
    )
)

endlocal
exit /B

该脚本基于以下事实:不会出现重复的环境变量,具有相同的名称。

此代码仅在满足以下条件时才有效:

  • 文件内容以不区分大小写的方式处理;
  • 输出文件中的行顺序无关紧要;
  • 第一个=符号前面的部分字符串以%%开头,并且至少包含一个%以外的字符;
  • 除了前导=之外,第一个%%之前的部分字符串仅包含可能出现在环境变量名称中的字符;
  • 第一个=后的部分字符串不能为空;
  • 第一个=后的部分字符串不得以=开头;
  • 文件中不允许感叹号!,因为它们可能会丢失或导致其他意外结果;

以下是使用临时文件的替代方法:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set "INFILE=%~1"
set "OUTFILE=%~2"
if not defined INFILE exit /B 1
if not defined OUTFILE set "OUTFILE=con"
set "TEMPFILE=%TEMP%\%~n0_%RANDOM%.tmp"

> "%TEMPFILE%" break
> "%OUTFILE%" (
    for /F usebackq^ delims^=^ eol^= %%L in ("%INFILE%") do (
        for /F tokens^=1^,*^ delims^=^=^ eol^= %%E in ("%%L") do (
            > nul 2>&1 findstr /I /X /L /C:"%%E" "%TEMPFILE%" || (
                echo(%%L
                >> "%TEMPFILE%" echo(%%E
            )
        )
    )
)
> nul 2>&1 del "%TEMPFILE%"

endlocal
exit /B

留给第一个=符号的每个唯一(非空)令牌都写入临时文件,该文件在从输入文件中读取每一行后进行搜索。如果令牌已在临时文件中可用,则跳过该行;如果没有,则将其写入输出文件。

除非您从/I命令中删除findstr开关,否则将以不区分大小写的方式处理文件内容。

更新:改进的脚本

这里有两个经过改进的脚本,因此没有特殊字符可以使它们失败。他们不使用临时文件。两个脚本都删除具有重复关键字的行(例如,在第一个=符号之前的部分字符串)。

如果遇到重复的关键字,此脚本会保留第一行行:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set "INFILE=%~1"
set "OUTFILE=%~2"
if not defined INFILE exit /B 1
if not defined OUTFILE exit /B 1

> "%OUTFILE%" break
for /F usebackq^ delims^=^ eol^= %%L in ("%INFILE%") do (
    for /F tokens^=1^ delims^=^=^ eol^= %%E in ("%%L") do (
        set "LINE=%%L"
        set "KEY=%%E"
        setlocal EnableDelayedExpansion
        if not "!LINE:~,1!"=="=" (
            set "KEY=!KEY:  = !"
            set "KEY=!KEY:\=\\!" & set "KEY=!KEY:"=\"!"
            more /T1 "%OUTFILE%" | > nul 2>&1 findstr /I /M /B /L /C:"!KEY!=" || (
                >> "%OUTFILE%" echo(!LINE!
            )
        )
        endlocal
    )
)

endlocal
exit /B

如果遇到重复的关键字,此脚本会保留 last 行:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

set "INFILE=%~1"
set "OUTFILE=%~2"
if not defined INFILE exit /B 1
if not defined OUTFILE exit /B 1

> "%OUTFILE%" (
    for /F delims^=^ eol^= %%L in ('findstr /N /R "^" "%INFILE%"') do (
        set "LINE=%%L"
        for /F "delims=:" %%N in ("%%L") do set "LNUM=%%N"
        setlocal EnableDelayedExpansion
        set "LINE=!LINE:*:=!"
        if defined LINE if not "!LINE:~,1!"=="=" (
            for /F tokens^=1^ delims^=^=^ eol^= %%E in ("!LINE!") do (
                setlocal DisableDelayedExpansion
                set "KEY=%%E"
                setlocal EnableDelayedExpansion
                set "KEY=!KEY:  = !"
                set "KEY=!KEY:\=\\!" & set "KEY=!KEY:"=\"!"
                more /T1 +!LNUM! "%INFILE%" | > nul 2>&1 findstr /I /M /B /L /C:"!KEY!=" || (
                    echo(!LINE!
                )
                endlocal
                endlocal
            )
        )
        endlocal
    )
)

endlocal
exit /B

对于这两个脚本,以下规则适用:

  • 维护具有非重复关键字的行的顺序;
  • 空行被忽略,因此被删除;
  • 空关键字,即以=开头的行,将被忽略,因此会被删除;
  • 完全不包含=的非空行将被视为以=结束以检查重复项,因此整行用作关键字; < / LI>
  • 检查重复项,每个 TAB 字符替换为单个 SPACE ;
  • 传输到返回文件的每一行都是从原始文件中复制而不进行更改(因此上述附件= TAB 的替换不会反映在那里);
  • 检查重复项是以不区分大小写的方式完成的,除非您从/I命令中删除findstr开关;

修订:处理多个文件

以上所有脚本仅用于处理单个文件。但是,如果您需要处理多个文件,您只需编写一个包含for循环的包装器,枚举所有输入文件,并为每个项调用上面的一个脚本(称为rem-dups.bat) - 像这样:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem Define constants here:
set "INPATH=D:\Data\source"  & rem (location of input files)
set "OUTPATH=D:\Data\target" & rem (location of output files)
set INFILES="source.txt" "test*.txt" & rem (one or more input files)
set "OUTSUFF=_no-dups" & rem (optional suffix for output file names)
set "SUBBAT=%~dp0rem-dups.bat"

pushd "%INPATH%" || exit /B 1
for %%I in (%INFILES%) do if exist "%%~fI" (
    call "%SUBBAT%" "%%~fI" "%OUTPATH%\%%~nI%OUTSUFF%%%~xI"
)
popd

endlocal
exit /B

您不能为输入和输出文件指定相同的位置。如果要覆盖原始输入文件,首先需要将修改后的输出文件写入另一个位置,然后将它们移回源位置 - 假设您已将包装器脚本中的OUTSUFF设置为空字符串(set "OUTSUFF="而不是set "OUTSUFF=_no-dups")。覆盖原始输入文件的命令行为:move /Y "D:\Data\target\*.*" "D:\Data\source"