0

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

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

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

@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|山姆;3 次;第 4 & 5 & 6 行

4

3 回答 3

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

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

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

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

于 2013-05-13T15:12:06.580 回答
0

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

@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 行
于 2013-05-13T18:40:22.590 回答
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 和 3 视为关键字段:

prog.bat 1 3

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

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

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

于 2013-05-15T02:57:49.383 回答