Board logo

标题: [文本处理] BAT脚本如何批量按行合并2个不同文件夹下的同名txt文件 [打印本页]

作者: allenyzq147    时间: 2018-1-29 18:27     标题: BAT脚本如何批量按行合并2个不同文件夹下的同名txt文件

按版主建议,把示例文档和5楼更新后的需求一并上传。

小妹是新手,弄了好几天了,始终搞不定。只有求大神哥哥们帮帮忙了。

我有2个文件夹,下面有大量同名txt文件:
文件夹eng1246的路径 C:\Users\CH6\Desktop\TEDTXTUNICODE\eng1246
文件夹chs1203的路径 C:\Users\CH6\Desktop\TEDTXTUNICODE\chs1203

文件夹eng1246下有1246个txt文件,文件名无规律
文件夹chs1203下有1203个txt文件,基本上每一个在文件夹eng1246下都有对应的同名文件(个别也许没有)

文件夹eng1246里有一些多余文件,在文件夹chs1203下没有对应文件。

现需要把在2个文件夹下的同名文件两两按行合并,形成新的txt文件,仍用原名,输出到一个新的文件夹内(新文件夹路径 C:\Users\CH6\Desktop\TEDTXTUNICODE\merge)。

每一个新文本XXX的格式如下:

文件夹eng1246下文本XXX的第一行  文件夹chs1203下文本XXX的第一行(中间用1个空格隔开)
文件夹eng1246下文本XXX的第二行  文件夹chs1203下文本XXX的第二行(中间用1个空格隔开)
文件夹eng1246下文本XXX的第三行  文件夹chs1203下文本XXX的第三行(中间用1个空格隔开)
。。。
。。。
所有合并后的新文本里的 行号、时间轴、空行 都给删除(此为5楼更新后的需求)

先谢谢各位老大了。
作者: 523066680    时间: 2018-1-29 18:49

本帖最后由 523066680 于 2018-1-30 10:06 编辑

字幕?

Perl

2018-01-30 更新


作者: yhcfsr    时间: 2018-1-29 22:04

PowerShell
保存为ps1扩展名文件,右键单击脚本,以powershell运行
未对powershell进行过设置的,可以管理员身份运行CMD,复制此命令到命令提示符 powershell -c "set-executionpolicy unrestricted" 以解除脚本限制
WIN10以下系统如出错,可能需要去微软官网下载补丁升级powershell

根据5楼的要求,更新了下代码
  1. $SD_eng=Get-ChildItem -Path "C:\Users\CH6\Desktop\TEDTXTUNICODE\eng1246"
  2. $SD_chs=Get-ChildItem -Path "C:\Users\CH6\Desktop\TEDTXTUNICODE\chs1203"
  3. $OD_merge="C:\Users\CH6\Desktop\TEDTXTUNICODE\merge"
  4. foreach($file_eng in $SD_eng){
  5.      $content=$content_eng=$content_chs=$null;
  6.      foreach($file_chs in $SD_chs){
  7.         if($file_eng.name -eq $file_chs.name){
  8.             $content_eng=Get-Content -Path $file_eng.FullName;
  9.             $content_chs=Get-Content -Path $file_chs.FullName;
  10.             break;
  11.         }#if
  12.       }#for2  
  13.       if(($content_eng.Count-$content_chs.Count) -ge 0){$count=$content_eng.Count}else{$count=$content_chs.Count;}
  14.      for($i=2;$i -le $count;$i+=4){
  15.         if ($content_eng[$i-2] -ne $content_chs[$i-2]){-join('文件',$file_eng.name,"`t在第",(($i-2)/4+1),'行号不对应');}
  16.         if ($content_eng[$i-1] -ne $content_chs[$i-1]){-join('文件',$file_eng.name,"`t在第",(($i-2)/4+1),'时间轴不对应');}
  17.         if(!($content_eng[$i])){-join('文件',$file_eng.name,"`t在第",(($i-2)/4+1),'无英文字幕');}
  18.         if(!($content_chs[$i])){-join('文件',$file_eng.name,"`t在第",(($i-2)/4+1),'无中文字幕');}
  19.         $content+=-join($content_eng[$i]," ",$content_chs[$i]+"`r`n");
  20.       }
  21.       if($content){$OF_name=$OD_merge+'\'+$file_eng.name;$content|Out-File -FilePath $OF_name;}
  22. }
  23. pause;
复制代码

作者: allenyzq147    时间: 2018-1-29 23:35

本帖最后由 allenyzq147 于 2018-1-29 23:36 编辑

回复 2# 523066680


    感谢您的回答。

    大神好眼力啊。的确是字幕文件,我是用来做语料库的。

    第一次运行Perl脚本
    我安装了StrawberryPerl,运行脚本后,只生成了一个TEDTXTUNICODE文件夹,这个文件夹下面有一个空的merge文件夹。
    是不是我装的软件不对.
作者: allenyzq147    时间: 2018-1-29 23:55

回复 3# yhcfsr

感谢你了,这位哥哥。文件已成功合并。不然一千多份文件,一行一行,非要了我的小命。

可是,由于我提问之前考虑不够周全,出现了新的问题:行号、时间轴、还有空行,这3行都是不需要的。
只要留一行一行的英文和中文的文字就可以了。

能不能麻烦哥哥你,
再给写个脚本把merge文件夹里所有的文本里的 行号、时间轴、空行 都给删除
或者把刚才的脚本给改一下,我重新合并也可以。

再次感谢!

刚才合并后的每一个新文本,都是下面这样的格式,随机打开了一个,随机复制了几行:

11 11
00:00:39,000 --> 00:00:41,000 00:00:39,000 --> 00:00:41,000
We didn't know 我们不知道

12 12
00:00:41,000 --> 00:00:43,000 00:00:41,000 --> 00:00:43,000
if he had perished yet 是否他还活着

13 13
00:00:43,000 --> 00:00:46,000 00:00:43,000 --> 00:00:46,000
until 36 hours later. 直到事发36小时之后。

最终结果需要是下面的样子:

We didn't know 我们不知道
if he had perished yet 是否他还活着
until 36 hours later. 直到事发36小时之后。
作者: 523066680    时间: 2018-1-30 08:54

本帖最后由 523066680 于 2018-1-30 09:01 编辑

回复 4# allenyzq147


    你需要把

my $path_eng = '.\TEDTXTUNICODE\eng1246';
my $path_chs = '.\TEDTXTUNICODE\chs1203';
my $path_merge = '.\TEDTXTUNICODE\merge';

这三行的路径改成你自己的,以及按你更新后的需求,最好是打包几个eng和chn的文件样本发上来,或者完整的打包发到网盘。
不然别人帮你解决问题,还得自己模拟文件环境,自己测试自己校验,最后发现需求改了?
作者: 慕夜蓝化    时间: 2018-1-30 10:06

  1. @echo off
  2. Setlocal enabledelayedexpansion
  3. set "txtPath1=C:\Users\CH6\Desktop\TEDTXTUNICODE\eng1246"
  4. set "txtPath2=C:\Users\CH6\Desktop\TEDTXTUNICODE\chs1203"
  5. for /f "delims=" %%i in ('dir /b/l/aa %txtPath1%\*.txt') do (
  6. for /f "delims=" %%a in ('dir /b/l/aa %txtPath2%\*.txt') do (
  7. if "%%i"=="%%a" (
  8. echo,%%i %%a 组合后。
  9. for /f "usebackq tokens=1,* delims=:" %%t in (`findstr /n "." "%txtPath1%\%%i"`) do (
  10. for /f "usebackq tokens=1,* delims=:" %%c in (`findstr /n "." "%txtPath2%\%%a"`) do (
  11. if "%%c"=="%%t" echo,%%u %%d
  12. )
  13. )
  14. )
  15. )
  16. )
  17. pause
复制代码

作者: 慕夜蓝化    时间: 2018-1-30 10:40

  1. import java.io.BufferedReader;
  2. import java.io.File;
  3. import java.io.FileReader;
  4. import java.io.IOException;
  5. public class BRDemo {
  6. public static void main(String args[]) throws IOException{
  7. String txtPath1 = "C:\\Users\\CH6\\Desktop\\TEDTXTUNICODE\\eng1246";
  8. String txtPath2 = "C:\\Users\\CH6\\Desktop\\TEDTXTUNICODE\\chs1203";
  9. File f1 = new File(txtPath1);
  10. File f2 = new File(txtPath2);
  11. File fs1[] = null;
  12. if(f1.isDirectory()){
  13. fs1 = f1.listFiles((File ff,String name) -> {if(name.endsWith(".txt")){return true;}return false;});
  14. }
  15. File fs2[] = null;
  16. if(f2.isDirectory()){
  17. fs2 = f2.listFiles((File ff,String name) -> {if(name.endsWith(".txt")){return true;}return false;});
  18. }
  19. for(File fa : fs1){
  20. System.out.println("------------------------");
  21. System.out.println(fa.getPath());
  22. for(File fb : fs2){
  23. if(fa.getName().equals(fb.getName())){
  24. BufferedReader bra = new BufferedReader(new FileReader(fa));
  25. BufferedReader brb = new BufferedReader(new FileReader(fb));
  26. int na = 0;
  27. int nb = 0;
  28. String braStr;
  29. String brbStr;
  30. while(bra.ready()){
  31. na++;
  32. while(brb.ready()){
  33. nb++;
  34. if(nb == na){
  35. System.out.println(bra.readLine() + " " + brb.readLine());
  36. }
  37. nb = 0;
  38. }
  39. na = 0;
  40. }
  41. }
  42. }
  43. }
  44. }
  45. }
复制代码

作者: 523066680    时间: 2018-1-30 11:00

更新:

1. chdir 路径 or 题主路径,这样不改代码就可以在我的目录和题主的环境上运行
  1. chdir '.\TEDTXTUNICODE' or
  2. chdir 'C:\Users\CH6\Desktop\TEDTXTUNICODE' or quit( $! );
复制代码
2. 增加时间轴匹配,时间对应才合并,如果没有匹配到时间会提示 missing $time at $filename



测试《雷神》字幕(手动去掉了一个时间轴)
Processing .\merge\Thor.txt
  missing 00:00:54 at .\chs1203\Thor.txt


.\merge\Thor.txt
Now, I know what you're thinking. 我知道你在想什么
"Oh, no! Thor's in a cage. How did this happen?" 不  托尔被关在笼子里了  怎么回事
Well, sometimes you have to get captured 有时  你得先被抓住
just to get a straight answer out of somebody. 才能从某人那里问出个所以然来
It's a long story, but basically, I'm a bit of a hero. 说来话长  但其实  我算是个英雄


分享个雷神字幕的示例包裹,含目录结构
作者: yhcfsr    时间: 2018-1-30 12:21

回复 5# allenyzq147
更新后的代码还放在二楼
作者: allenyzq147    时间: 2018-1-30 13:10

回复 6# 523066680


    感谢您的耐心,我已经把示例文档和更新后的需求都上传到一楼的附件里了。

更新后的perl脚本我测试了,雷神字幕的确正常合并,但我的字幕合并就是不成功。
按你第一次更新的脚本测试,merge文件夹里出现了合并后的文本,但打开全是乱码。
按你第二次更新的脚本测试,merge文件夹里也出现了合并后的文本,但全是空文本。
作者: allenyzq147    时间: 2018-1-30 13:13

回复 10# yhcfsr


    已经按更新后的脚本成功合并,并删除不需要的行。
    给你一个大大的

    再次表示感谢!
作者: allenyzq147    时间: 2018-1-30 13:18

回复 8# 慕夜蓝化


    感谢您的回复!

我按您第一回复的批处理脚本运行,有窗口显示在处理文本,但近半小时依然没有处理完,不得以暂停、关闭了。merge文件夹里没有得到任何合并后的文本。

第二次更新是java脚本吗,可我并不知道怎么运行。

虽然没成功,依然感谢您的热心。
作者: 慕夜蓝化    时间: 2018-1-30 14:05

回复 13# allenyzq147


    嗯,非成品,你需要加个括号以及重定向符,导入到指定的文件夹中就可以。
作者: 523066680    时间: 2018-1-30 15:27

回复 11# allenyzq147

    哦,原来是 utf16-le 的编码。代码更新在附件,附输出结果(发现Adam Grosser的一些时间段是没有中文翻译的,如果按行合并,就会错乱。)
  1. Processing .\merge\A TED speakers worst nightmare.txt
  2. Processing .\merge\Adam Grosser - A mobile fridge for vaccines.txt
  3.   missing 00:00:28 at .\chs1203\Adam Grosser - A mobile fridge for vaccines.txt
  4.   missing 00:00:29 at .\chs1203\Adam Grosser - A mobile fridge for vaccines.txt
  5.   missing 00:00:31 at .\chs1203\Adam Grosser - A mobile fridge for vaccines.txt
  6.   missing 00:00:33 at .\chs1203\Adam Grosser - A mobile fridge for vaccines.txt
  7.   missing 00:00:37 at .\chs1203\Adam Grosser - A mobile fridge for vaccines.txt
  8.   ...
  9. Processing .\merge\Ahn Trio - A modern take on piano violin cello.txt
  10. Done
复制代码
我现在的处理方式是按时间段匹配,如果没有对应翻译就不输出。
作者: allenyzq147    时间: 2018-1-30 17:05

回复 15# 523066680

   
    非常感谢版主大人。

    刚测试了你更新后的代码,非常顺利,便于我把一些时间线不匹配的字幕找出来。
   
    这段代码与前面代码区别在哪里?
    你上一段代码只对UTF-8编码的文本起作用吗?
作者: allenyzq147    时间: 2018-1-30 17:12

回复 14# 慕夜蓝化


    作为一个处女座,我还是没忍住安装了JDK,配置了环境变量,测试了那段JAVA代码。

结果
:6:错误:类BRDemo是公共的,应在名为BRDemo.java的文件中声明......bla bla
作者: 523066680    时间: 2018-1-30 17:16

本帖最后由 523066680 于 2018-1-30 17:39 编辑

回复 16# allenyzq147

    上一段代码只对 utf8 gbk 之类(这类编码和 ASCII 码兼容)的编码起作用。现在的代码只对  utf16-le 编码起作用。
旧代码的问题以及原因:utf16-le 对 ASCII 范围的编码补0,扩充到两个字节,这样换行\r\n就不是 0d 0a, 而是 0d 00 0a 00,匹配换行的时候就会有差异。
作者: allenyzq147    时间: 2018-1-30 22:53

回复 18# 523066680


    感谢版主大神这么耐心的解释。

    再次感谢所有答题的哥哥们。
作者: 慕夜蓝化    时间: 2018-1-31 15:19

回复 17# allenyzq147


    哈哈,你还是蛮可爱的。嗯,需要jdk8,你安装好之后。在桌面新建一个txt文档,将代码复制到文本中,并将文件名更改为BRDemo.java。保存完毕后,win7下shift鼠标右键->在此处打开命令窗口。输入 javac BRDemo.java 回车。 会生成一个class 文件。 然后,在命令窗口中继续输入 java BRDemo ,即可看到打印出的信息。如果在这个过程中有不明了的,可以加下我q,1451979729,也欢迎各位添加,共同交流。
作者: WHY    时间: 2018-2-1 11:31

本帖最后由 WHY 于 2018-2-2 22:24 编辑
  1. function MergeFiles($chsFile, $engFile){
  2.     $hash = @{}; $s1 = $s2 = '';
  3.     ForEach($strLine In (type $chsFile)){
  4.         If($s1 -like '[0-9][0-9]:*') { $hash[$s1] = $strLine; }
  5.         $s1 = $strLine;
  6.     }
  7.     ForEach($strLine In (type $engFile)){
  8.         If($s2 -like '[0-9][0-9]:*'){$strLine + ' ' + $hash[$s2];}
  9.         $s2 = $strLine;
  10.     }
  11. }
  12. $chsDir = 'C:\Users\CH6\Desktop\TEDTXTUNICODE\chs1203';
  13. $engDir = 'C:\Users\CH6\Desktop\TEDTXTUNICODE\eng1246';
  14. $mergeDir = 'C:\Users\CH6\Desktop\TEDTXTUNICODE\merge';
  15. If(!(Test-Path $mergeDir)){$null = md $mergeDir;}
  16. ForEach($eng In (dir ($engDir + '\*.txt'))){
  17.     $chsFile = $chsDir + '\' + $eng.Name;
  18.     If(Test-Path $chsFile){
  19.         $arr = MergeFiles $chsFile $eng.FullName;
  20.         Set-Content ($mergeDir + '\' + $eng.Name) $arr -Enc unicode;
  21.     }
  22. }
  23. [Console]::Write('Done');
  24. [Console]::ReadLine()
复制代码





欢迎光临 批处理之家 (http://www.bathome.net/) Powered by Discuz! 7.2