【问题标题】:Batch Script - muliple duplicate strings in a row批处理脚本 - 连续多个重复的字符串
【发布时间】:2013-05-07 13:23:39
【问题描述】:

下面的脚本提供了 token#1 字段每次出现的输出,但我需要再添加两个条件。

一个。应提供输出。即只有当它超过一个时,因为我在一个文件中有数百万条记录

b.如果有多个字符串。即一行中的关键字段组合需要检查文件中所有行的重复项。

@ECHO OFF

SETLOCAL enabledelayedexpansion
FOR %%c IN ($ #) DO FOR /f "delims==" %%i IN ('set %%c 2^>nul') DO
"SET %%i="

SET /a count=0

FOR /f "tokens=1delims=|" %%i IN (fscif.txt) DO (
 SET /a count+=1

 IF DEFINED $%%i (SET "$%%i=!$%%i! & !count!") ELSE (SET "$%%i=!count!")
  SET /a #%%i+=1 )

 FOR /f "tokens=1*delims=$=" %%i IN ('set $ 2^>nul') DO (  ECHO %%i;!#%%i! times;line no %%j 
)

例如: 原始文件(考虑到令牌 1 和 3 是关键字段)

123|12|杰克

124|23|约翰

123|14|杰克

125|15|山姆

125|66|山姆

125|66|山姆

输出文件:

123|Jack;2 次;第 1 行和第 3 行

125|Sam;3 次;第 4 & 5 & 6 行

【问题讨论】:

  • 批处理无法处理“百万条记录”。将您的记录放入 SQL 数据库中。
  • 我不明白为什么不这样做。这可能需要一段时间,如果有人能想到解决环境问题的方法,一个简单的批处理程序可能就可以了。

标签: string batch-file many-to-many duplicates


【解决方案1】:
@ECHO OFF
SETLOCAL enabledelayedexpansion
:: Temporary filename
:tloop
SET "temppfx=%temp%\%random%"
IF EXIST "%temppfx%*" GOTO tloop
:: Hold that tempfile name...
ECHO.>"%temppfx%_"

:: a long string of spaces note the end-of-string quote -----here--v
SET "spaces=                                                       "
SET /a count=0

(
FOR /f "tokens=1,3 delims=|" %%a IN (fscif.txt) DO (
 SET /a count+=1
 SET "field1=%%a%spaces%"
 SET "field3=%%b%spaces%"
 SET "fieldc=%spaces%!count!"
 ECHO(!field1:~0,10!!field3:~0,12!^|!fieldc:~-8!^|!count!^|%%a^|%%b
)
)>"%temppfx%1"

:: Now report

SET "key=x"
SET /a count=0

(
FOR /f "tokens=1,3* delims=|" %%a IN ('sort "%temppfx%1" ') DO (
 IF "!key!"=="%%a" (
  SET "line=!line! %%b"
  SET /a count+=1
 ) ELSE (IF !count! neq 0 CALL :output
         SET key=%%a
     SET line=%%b
     SET "data=%%c"
         SET /a count=1
     )
)
CALL :output
)>report.txt

del "%temppfx%*"
GOTO :eof

:output
ECHO(!data!;%count% times;line nos %line: = ^& %

GOTO :eof

正如我之前解释的,有数百万条记录,您可能会用完环境空间。如上所述,我认为您可能仍然会用完,因为行号报告可能很大 - 不知道 - 您熟悉您的真实数据。

本质上,首先要做的是建立一个临时文件。

从输入文件中所需的标记开始——我遵循了 1 和 3,但毫无疑问可能还有更多——只要跟着弹跳球…

使用spaces 变量填充所选字段 - 右侧用于文本字段,左侧用于计数字段。

然后生成临时文件输出。我随机选择第一个字段的最大长度为 10,第二个字段的最大长度为 12。这两者结合起来给出了key 字段。前导填充的计数字段作为第二列输出,以便在SORTing 之后,数据将按键分组,然后是行号。然后复制剩余的感兴趣的列。

然后将数据排序为下一个 for/f 循环的输入 - 只有标记 1(键)、3(原始行号)和“其余”(没有填充的键)感兴趣

然后只需计算匹配键并在line 中累积行号并在键更改时报告。需要最后一个输出来报告最后一个数据项,我们就完成了。

【讨论】:

    【解决方案2】:

    对于这个丑陋的批处理作业,我建议使用来自GNUWin 项目的seduniq

    @echo off&setlocal enabledelayedexpansion
    set "inputfile=file"
    set "outputfile=out"
    set "tempfile=%temp%\%random%"
    <"%inputfile%" sed "s/|.*|/|.*|/"|sort|uniq -d>"%tempfile%"
    (for /f "usebackqtokens=1-3delims=|" %%i in ("%tempfile%") do (
        set /a cnt=0&set "line="
        for /f "delims=:" %%a in ('findstr /nr "%%i|%%j|%%k" "%inputfile%"') do set "line=!line!%%a & "&set /a cnt+=1
        echo(%%i^|%%k;!cnt! times;line no !line:~0,-3!
    ))>"%outputfile%"
    del "%tempfile%"
    type "%outputfile%"
    

    .. 输出是:

    123|杰克;2 次;第 1 行和第 3 行 125|山姆;3 次;第 4 & 5 & 6 行

    【讨论】:

      【解决方案3】:

      下面的批处理文件做你想做的事:

      @echo off
      setlocal EnableDelayedExpansion
      
      rem Assemble "tokensValues" and "lastToken" variables from the parameters
      set letters=0abcdefghijklmnopqrstuvwxyz
      set tokensValues=%%!letters:~%1,1!
      set lastToken=%1
      :nextArg
         shift
         if "%1" equ "" goto endArgs
         set "tokensValues=!tokensValues!@%%!letters:~%1,1!"
         set lastToken=%1
         goto nextArg
      :endArgs
      
      rem Accumulate duplicated strings
      set line=0
      for /F "tokens=1-%lastToken% delims=|" %%a in (fscif.txt) do (
         set /A line+=1
         if not defined lines[%tokensValues%] (
            set lines[%tokensValues%]=!line!
         ) else (
            set "lines[%tokensValues%]=!lines[%tokensValues%]! & !line!"
         )
         set /A times[%tokensValues%]+=1
      )
      
      rem Show the result
      for /F "tokens=2* delims=[]=" %%a in ('set lines[ 2^>NUL') do (
         if !times[%%a]! gtr 1 (
            set string=%%a
            set "string=!string:@=|!"
            echo !string!;!times[%%a]! times;line no %%b
         )
      )
      

      您必须在参数中提供所需关键字段的数量。例如,将 1 和 3 视为关键字段:

      prog.bat 1 3
      

      您最多可以提供 26 个关键字段,位置从 1 到 26;这个限制可以很容易地增加到 52。

      此批处理文件不使用任何外部命令,而是在原始文件上运行,因此它应该运行得很快。如果文件很大,使用sortfindstr 命令将花费很长时间(即使是简单的copy,同样如此)。

      如果我们以您的示例数据作为真实数据的代表,lines 变量应该存储大约 2500-3000 行(即相同关键字段出现的不同行数),并且总环境空间为64 MB 我认为这个程序将能够处理您的大文件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-05-17
        • 1970-01-01
        • 2014-06-14
        相关资源
        最近更新 更多