批处理脚本 - 连续多个重复的字符串

时间:2013-05-13 13:27:33

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

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

一个。应提供输出。即。因为我在文件中有数百万条记录

,所以只有它不止一个

湾如果有多个字符串.i.e。需要检查行中的关键字段的组合,以检查文件中的重复项。

@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 |杰克; 2次; 1号线& 3

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

3 个答案:

答案 0 :(得分:0)

@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变量在计数字段的左侧。

然后生成tempfile输出。我随机选择第一个字段的最大长度为10,第二个字段的最大长度为12。这两个结合起来给出key字段。前导填充计数字段作为第二列输出,以便在SORT之后,数据将按键分组,然后按行号分组。然后再现其余感兴趣的列。

然后将数据作为输入分类到下一个for/f循环 - 只有令牌1(密钥),3(原始行号)和“其余”(没有填充的密钥)是感兴趣的

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

答案 1 :(得分:0)

对于这个丑陋的批处理作业,我建议使用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|Jack;2 times;line no 1 & 3
125|Sam;3 times;line no 4 & 5 & 6

答案 2 :(得分:0)

下面的批处理文件可以执行您想要的操作:

@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&amp; 3作为关键字段:

prog.bat 1 3

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

此批处理文件不使用任何外部命令并对原始文件起作用,因此它应该快速运行。如果文件很大,则sortfindstr命令会花费太长时间(即使是简单的copy)。

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