Board logo

标题: [文本处理] 求助改进循环将一个文本的每一行重复指定次数后按每隔指定行数插入到另一个文本 [打印本页]

作者: q4911    时间: 2015-4-18 15:48     标题: 求助改进循环将一个文本的每一行重复指定次数后按每隔指定行数插入到另一个文本

本帖最后由 pcl_test 于 2016-8-9 18:18 编辑

我有一个bat,但是处理时间太长了,如何让这个bat处理速度变快
  1. @echo off&setlocal enabledelayedexpansion
  2. set/p file=拖入需要修改的文件并回车:
  3. set/p src=拖入需要增加的文件并回车:
  4. set/p count=输入每隔多少行插入:
  5. set/p blank=输入插入多少行:
  6. for /f "delims=" %%i in ('type %src%')do set/ai+=1&set "#!i!=%%i"
  7. (for /f "usebackq delims=" %%a in (%file%) do (
  8.   echo,%%a
  9.   set/a n+=1,m=n%%count
  10.   if !m! equ 0 set/aj+=1&for /l %%b in (1 1 %blank%)do for %%i in (!j!)do echo,!#%%i!
  11.   if !j! equ !i! set j=0
  12. ))>new.txt
  13. start new.txt
复制代码
这个bat数据处理速度太慢了,请教一下大神怎么样才能变成快速?
作者: BAT1    时间: 2015-4-18 15:50

本帖最后由 BAT1 于 2015-4-18 15:52 编辑

文件有多大?搞个样本试试.
作者: q4911    时间: 2015-4-18 15:52

这个是插入数据
这个是源文件
都是随便写的,测试用
作者: q4911    时间: 2015-4-18 16:13

回复 2# BAT1


看楼上。。
作者: q4911    时间: 2015-4-20 13:49

求帮忙。
作者: gawk    时间: 2015-4-20 13:58

回复 3# q4911


    真实的“原文件.txt”和“插入数据.txt”分别有多大?使用顶楼的代码处理需要多长时间?
作者: q4911    时间: 2015-4-21 13:53

回复 6# gawk


   真实原文件大概是10~20MB,插入数据大概是几十KB。
  因为上传文件不能提交超过一定MB的文件,只要把源文件的内容随便一直往下复制到一定大小就可以测试了。插入数据也可以随便写。
  之前我的处理时间至少要十分钟吧。
作者: gawk    时间: 2015-4-21 15:08

回复 7# q4911


    传到百度网盘吧
作者: xxpinqz    时间: 2015-4-21 19:23

纯批来处理这么大文件,不死机算好了。。。
作者: q4911    时间: 2015-4-28 14:17

回复 8# gawk


测试的文本我上传到百度网盘了 http://pan.baidu.com/s/1eQ90DPK
作者: CrLf    时间: 2015-4-28 15:52

本帖最后由 CrLf 于 2015-4-28 16:24 编辑

这么大的变量表,读写起来非常慢的
尤其是你的代码中以 # 开头的一大坨变量在变量表中太靠前,严重影响 j、n 等高频变量的引用耗时,简单的办法是把 # 改成 x、y、z 之类比较靠后的变量,并在引用之后立即把没用的变量删除,就会快多了
  1. @echo off&setlocal enabledelayedexpansion
  2. set/p file=拖入需要修改的文件并回车:
  3. set/p src=拖入需要增加的文件并回车:
  4. set/p count=输入每隔多少行插入:
  5. set/p blank=输入插入多少行:
  6. for /f "delims=" %%i in ('type %src%')do set/ai+=1&set "z!i!=%%i"
  7. set "n=%count%"
  8. (for /f "usebackq delims=" %%a in ("%file:"=%") do (
  9.   echo,%%a
  10.   set/a n-=1
  11.   if !n! leq 0 (
  12.     for %%i in (!j!)do set "str=!#%%i!"&set "#%%i="
  13.     for /l %%b in (1 1 %blank%)do echo !str!
  14.     set "n=%count%"
  15.   )
  16. ))>new.txt
  17. start new.txt
复制代码

作者: q4911    时间: 2015-4-28 16:36

回复 11# CrLf


  如何通过  gawk 或者 sed 来加速处理bat呢?
作者: CrLf    时间: 2015-4-28 16:40

本帖最后由 CrLf 于 2015-4-28 16:44 编辑

这样可能更好,避开大坨变量:
  1. @echo off&setlocal enabledelayedexpansion
  2. set/p file=拖入需要修改的文件并回车:
  3. set/p src=拖入需要增加的文件并回车:
  4. set/p count=输入每隔多少行插入:
  5. set/p blank=输入插入多少行:
  6. set "n=%count%"
  7. (for /f "usebackq delims=" %%a in ("%file:"=%") do (
  8.   echo,%%a
  9.   set/a n-=1
  10.   if !n! leq 0 (
  11.     set "str="
  12.     set /p "str="
  13.     for /l %%b in (1 1 %blank%)do echo !str!
  14.     set "n=%count%"
  15.   )
  16. ))>new.txt <%src%
  17. start new.txt
复制代码

作者: CrLf    时间: 2015-4-28 17:37

实测13楼方案隔2行插入2次耗时如下:
  1. start at 16:43:49.16
  2. end at 16:47:12.32
复制代码
合计约3分半钟

同样设置下,顶楼方案的日志:
  1. start at 16:50:16.46
复制代码
截至发此帖时(17:35)仍在运行...

提升后的效率应该达到楼主的要求吧
作者: q4911    时间: 2015-4-28 17:48

回复 14# CrLf


    确实快了 很多 谢谢大神
作者: q4911    时间: 2015-4-28 18:46

本帖最后由 q4911 于 2015-4-28 19:08 编辑

回复 14# CrLf


    为什么处理结果文本会出现   ECHO 处于关闭状态。

    插入的数据没有循环。
作者: xxpinqz    时间: 2015-4-28 20:09

因为缺少了原代码中的一个判断:if !j! equ !i! set j=0
要能循环插入,貌似还是需要设置变量表。
作者: CrLf    时间: 2015-4-28 21:32

回复 17# xxpinqz


确实如此,没多想就顺手删了
如果用变量表保存文本,基本没有可优化的空间
所以派生出两种办法:
1、为 %src% 中的每行生成包含 %count% 个此行的小文件,引用时直接 type,这办法简单易行,不过文件多得让你崩溃
2、仍用 set /p str= <%src% 的办法,但为了处理 %file% 多于 %src% 的情况,需要事先倍增 %src% 到临时文件,已修改
  1. @echo off&setlocal enabledelayedexpansion
  2. set/p file=拖入需要修改的文件并回车:
  3. set/p src=拖入需要增加的文件并回车:
  4. set/p count=输入每隔多少行插入:
  5. set/p blank=输入插入多少行:
  6. set "n=%count%"
  7. for /f %%a in ('find /c /v ""^<%file%') do set file.count=%%a
  8. for /f %%a in ('find /c /v ""^<%src%') do set src.count=%%a
  9. findstr /v $ %src%&&echo;>>%src%
  10. copy /y %src% src.temp
  11. set /a loop.count = file.count / count / src.count
  12. for /l %%a in (1 1 %loop.count%) do copy /b src.temp+%src%
  13. (for /f "usebackq delims=" %%a in ("%file:"=%") do (
  14.   echo,%%a
  15.   set/a n-=1
  16.   if !n! leq 0 (
  17.     set "str="
  18.     set /p "str="
  19.     for /l %%b in (1 1 %blank%)do echo !str!
  20.     set "n=%count%"
  21.   )
  22. ))>new.txt <src.temp
  23. start new.txt
复制代码

作者: CrLf    时间: 2015-4-28 21:38

用大量临时文件的办法(不推荐),只对顶楼方案进行小改造,减少耗时的操作:
  1. @echo off&setlocal enabledelayedexpansion
  2. set/p file=拖入需要修改的文件并回车:
  3. set/p src=拖入需要增加的文件并回车:
  4. set/p count=输入每隔多少行插入:
  5. set/p blank=输入插入多少行:
  6. md 临时文件夹
  7. for /f "delims=" %%i in ('type %src%')do (
  8.   set/ai+=1
  9.   (for /l %%b in (1 1 %blank%)do echo,%%i)>临时文件夹\!i!.txt
  10. )
  11. (for /f "usebackq delims=" %%a in (%file%) do (
  12.   echo,%%a
  13.   set/a n+=1,m=n%%count
  14.   if !m! equ 0 (
  15.     set/aj+=1,j=j%%i+1
  16.     type 临时文件夹\!j!.txt
  17.   )
  18. ))>new.txt
  19. rd /s /q 临时文件夹
  20. start new.txt
复制代码

作者: q4911    时间: 2015-4-28 22:26

回复 19# CrLf


    谢谢 可以了
作者: pcl_test    时间: 2016-8-9 19:32

  1. /*&cls
  2. @echo off
  3. set /p file=拖入需要插入数据的文件并按回车:
  4. set /p src=拖入数据文件并按回车:
  5. set /p count=输入每隔多少行插入数据并按回车:
  6. set /p blank=输入每行数据插入多少次并按回车:
  7. cscript -nologo -e:jscript "%~f0" "%file%" "%src%" "%count%" "%blank%"
  8. pause&exit
  9. */
  10. if(!WSH.Arguments(0)||!WSH.Arguments(1)||!WSH.Arguments(2)||!WSH.Arguments(3)||!/[1-9][0-9]*/.test(WSH.Arguments(2))||!/[1-9][0-9]*/.test(WSH.Arguments(3)))WSH.echo('输入有误');
  11. var fso = new ActiveXObject('Scripting.FileSystemObject');
  12. var a = fso.OpenTextFile(WSH.Arguments(0), 1);
  13. var b = fso.OpenTextFile(WSH.Arguments(1), 1);
  14. var c = fso.CreateTextFile('结果.txt', 2);
  15. var btext = b.ReadAll().split(/\r?\n/);
  16. var n=m=0;
  17. while(!a.AtEndOfStream){
  18.     var line = a.ReadLine();
  19.     n++;
  20.     if(n%WSH.Arguments(2)==0){
  21.         var s='';
  22.         for(var i=0; i<WSH.Arguments(3); i++){
  23.             s+=btext[m]+'\r\n';
  24.         }
  25.         if(m==btext.length-1){m=0}else m++;
  26.         c.Write(line+'\r\n'+s);
  27.     }else c.Writeline(line);
  28. }
复制代码

作者: pcl_test    时间: 2016-8-9 20:24

第三方http://www.bathome.net/s/tool/index.html?key=gawk
  1. #* 2>nul 3>nul&cls&@echo off
  2. #*&set /p file=拖入需要插入数据的文件并按回车:
  3. #*&set /p src=拖入数据文件并按回车:
  4. #*&set /p count=输入每隔多少行插入数据并按回车:
  5. #*&set /p blank=输入每行数据插入多少次并按回车:
  6. #*&gawk -f "%~f0" "%file%" "%src%" "%count%" "%blank%"&pause&exit
  7. BEGIN{
  8.     result="结果.txt";
  9.     while(getline<ARGV[2]>0){
  10.         i++;b[i]=$0;
  11.     }
  12.     m=1;
  13.     while(getline<ARGV[1]>0){
  14.         n++;
  15.         if(n%ARGV[3]==0){
  16.             s="";
  17.             for(i=0; i<ARGV[4]; i++){
  18.                 s=s""b[m]"\n";
  19.             }
  20.             if(m==length(b)){m=1}else m++;
  21.             printf $0"\n"s>result;
  22.         }else print $0>result;
  23.     }
  24. }
复制代码





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