返回列表 发帖

[文本处理] 批处理怎样识别相同行的文本后移动文本内容?

论坛的大哥们帮我下,我想实现以下功能,谢谢!
1、我这边有3个txt文本,每个文本都有几千万行。(第一个文本demo.txt,第二个文本a.txt,第三个文本b.txt)
2、首先识别demo.txt的第一行内容,去a.txt里匹配,行与行匹配,完全一致的行才算匹配上。
3、再将demo.txt的第一行内容,去b.txt里匹配,行与行匹配,完全一致的行才算匹配上。
4、将匹配结果输出到result.txt里,格式为:demo.txt的第一行实际内容,a.txt存在,b.txt不存在,时间XXXX年XX月XX日XX点XX分XX秒
5、记录好日志之后,把这三个文本中的这行内容都给删除掉
6、接着识别demo.txt的第二行内容,以此类推。
7、因为数据量庞大,可能处理会很慢,所以在批处理的对话框(或者标题中)里要显示当前正在处理第几行,方便我评估剩余时间
8、因为数据量庞大,可能处理会很慢,所以最好是处理一行--记录日志--删除内容后接着处理第二行,如果所有文本的所有行一次性读取到内存里预处理的话可能让预处理的时间会很久很久
9、注意是行与行匹配,完全一致的行才算匹配上。
10、有个示例
demo.txt有三行数据
12
123
1


a.txt有三行数据
1
11
12


b.txt有5行数据
1
2
3
124
0125



result.txt为:
12,a.txt存在,b.txt不存在,2025年4月7日17点00分05秒
123,a.txt不存在,b.txt不存在,2025年4月7日17点00分08秒
1,a.txt存在,b.txt存在,2025年4月7日17点00分12秒

本帖最后由 aloha20200628 于 2025-4-8 14:47 编辑

回复 1# 304802301

以下代码存为 test.bat 与 demo.txt, a.txt, b.txt 同目录运行...
代码流程根据楼主要求的顺序/步骤,但须确保被处理的三个 *.txt 源文件是 ansi(gb2312 即简中)编码
备注》如果三个源文件各自均无重复文本行,亦可删除代码第8-9行,如此运行效率可能会提升...
@echo off &cd.>"result.txt" &set "n=0"
for /f "delims=" %%s in (demo.txt) do (
   set/a "n+=1" &call echo,正在处理第 %%n%% 行...
   set "s=%%s" &setlocal enabledelayedexpansion &set/p="!s!,">>"result.txt"
   (findstr /lx "!s!" "a.txt">nul)&(if !errorlevel! neq 0 (set/p="a.txt不存在,") else set/p="a.txt存在,")>>"result.txt"
   (findstr /lx "!s!" "b.txt">nul)&(if !errorlevel! neq 0 (set/p="b.txt不存在,") else set/p="b.txt存在,")>>"result.txt"
   echo,!date:~,4!!date:~5,2!!date:~8,2!!time:~,2!!time:~3,2!!time:~6,2!秒>>"result.txt"
   findstr /lxv "!s!" "a.txt">"_a.txt" &(move /y "_a.txt" "a.txt">nul)
   findstr /lxv "!s!" "b.txt">"_b.txt" &(move /y "_b.txt" "b.txt">nul)
   endlocal
) 2>nul <nul
pause&exit/bCOPY

TOP

本帖最后由 wanghan519 于 2025-4-8 09:53 编辑

存为ansi编码的bat,放到a.txt b.txt demo.txt以及下载的gawk.exe所在目录
#ANSI编码&cls&gawk -f "%~f0" demo.txt > result.txt&pause&exit/b
BEGIN{
    while((getline l < "a.txt")>0)a[l]++;close("a.txt");
    while((getline l < "b.txt")>0)b[l]++;close("b.txt");
}
{
    if(NR%100000==0)printf(NR"\r") > "/dev/stderr";
    printf $0;
    if(a[$0]){printf ",a.txt存在";a[$0]--}else{printf ",a.txt不存在"};
    if(b[$0]){printf ",b.txt存在";b[$0]--}else{printf ",b.txt不存在"};
    print ","strftime("%Y年%m月%d日%H点%M分%S秒",systime())
}COPY

TOP

本帖最后由 aloha20200628 于 2025-4-8 13:05 编辑

回复 1# 304802301

再给一个 bat+powershell 版本,存为 test.bat 与 demo.txt, a.txt, b.txt 同目录运行...
假设被处理的三个 *.txt 源文件均是 ansi(gb2312 即简中)编码
假设 powershell 一次性读入 *.txt 不会产生内存溢出,据此可省略处理过程中对 *.txt 源文件的反复删减
如果 demo.txt 文件有大量重复文本行,应先对其去重以便提高处理效率,为此代码采用了 powershell 的高速去重方法
当前行处理提示信息会在 cmd 运行窗口标题行上显示...
<# ::
@echo off &powershell -c "iex(${%~f0}|out-string)" &pause&exit/b
#>
$n=0; $a=gc 'a.txt' -readcount 1000; $b=gc 'b.txt' -readcount 1000
[Collections.Generic.HashSet[string]](gc 'demo.txt' -readcount 1000) | % {
   $host.UI.RawUI.WindowTitle='正在处理第'+ (++$n) +'行...'
   if ($_ -in $a) {$sa='a.txt存在'} else {$sa='a.txt不存在'}
   if ($_ -in $b) {$sb='b.txt存在'} else {$sb='b.txt不存在'}
   $_+','+$sa+','+$sb+','+(Get-Date -Format "yyyy年MM月dd日HH点mm分ss秒")
} | out-file 'result.txt' -enc default
exitCOPY
如果确认 demo.txt 文件中没有重复文本行,则可将以上代码中第5行改为 (gc 'demo.txt' -readcount 1000) | % { 即可

TOP

返回列表