[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

【出题】批处理给文本文件ab cd.txt每行前加上日期

出题:给ab cd.txt每行前加上日期
已知:
   ab cd.txt 文件名含空格。(不能改文件名)
   ab cd.txt 行数不确定 (大约5万行左右),无空行,且不含特殊符号。
.
要求:
   1、给ab cd.txt每行前面加上日期,将结果写入 c.txt
   2、最后一行为当前日期,倒数第二行为昨天的日期,倒数第三行为前天的日期,依此类
推。。。。
   3、并在跨月份时插入空行。
   如:09月30日 和 10月01日 之间需插入一空行。
  1.    2008年09月28日 为什么要学习批处理
  2.    2008年09月29日 1.源自于批处理的简单
  3.    2008年09月30日 我想没有多少人愿意花上一个月甚至更多的时间
  4.    2008年10月01日 去绞尽脑汁的专门学习一个编程语言来写一个删除系统垃圾的程序,
  5.    2008年10月02日 因为对于一个不是专门学习计算机或者将来从事这方面工作的人来说,
  6.    2008年10月03日 这样的投入与产出实在是不值得的,
  7.    2008年10月04日 而用我们的批处理只要几分钟就可以解决这个问题,
复制代码
代码要求:
  1、不产生临时文件
  2、用纯p解决。
  3、必须考虑跨年度、跨月份、及闰年的情况。
  4、代码运行耗时不能超过一分钟。
.
加分条件:
   1、效率高   +5
   2、代码简洁 +3
   3、满分    +10
.

假设ab cd.txt内容为:
  1. 为什么要学习批处理
  2. 1.源自于批处理的简单
  3. 我想没有多少人愿意花上一个月甚至更多的时间
  4. 去绞尽脑汁的专门学习一个编程语言来写一个删除系统垃圾的程序,
  5. 因为对于一个不是专门学习计算机或者将来从事这方面工作的人来说,
  6. 这样的投入与产出实在是不值得的,
  7. 而用我们的批处理只要几分钟就可以解决这个问题,
  8. 这样的方便性让任何对计算机望而生畏的人来说是多么的有吸引力。
  9. 2.通过批处理的编写,会逐渐的熟悉windows操作系统的一些细节问题,
  10. 仅此一点就能让你在众多菜鸟中脱颖而出。
  11. 3.通过diy自己的“程序”让自己有种成就感,
  12. 这种感觉绝对不是使用别人的工具所能言语的,
  13. 自己能写出来东西就是对自己最好的证明。
  14. 4.强大性,baidu,google里不可能搜索到能帮你解决掉所有问题的程序,
  15. 如果你不会写那些.exe程序,
  16. 那么你要完成你的目标可能就要花些银子让一些软件工作室帮你写咯。
  17. 其实决大部分系统的问题,.bat都可以轻松的帮你解决掉了。
  18. 说了这么多,到底为什么要学习批处理就是很简单的一句话:
  19. 程序是写出来满足绝大部分人的,而批处理是满足我们自己的。
  20. 每个拥有计算机和懂计算机的人都应该学习批处理。
  21. 因为世界上任何一个人都能通过简单的学习掌握批处理这门“编程语言”
复制代码
假设当前日期为: 2008年10月18日
要求 c.txt 结果如下:
  1. 2008年09月28日 为什么要学习批处理
  2. 2008年09月29日 1.源自于批处理的简单
  3. 2008年09月30日 我想没有多少人愿意花上一个月甚至更多的时间
  4. 2008年10月01日 去绞尽脑汁的专门学习一个编程语言来写一个删除系统垃圾的程序,
  5. 2008年10月02日 因为对于一个不是专门学习计算机或者将来从事这方面工作的人来说,
  6. 2008年10月03日 这样的投入与产出实在是不值得的,
  7. 2008年10月04日 而用我们的批处理只要几分钟就可以解决这个问题,
  8. 2008年10月05日 这样的方便性让任何对计算机望而生畏的人来说是多么的有吸引力。
  9. 2008年10月06日 2.通过批处理的编写,会逐渐的熟悉windows操作系统的一些细节问题,
  10. 2008年10月07日 仅此一点就能让你在众多菜鸟中脱颖而出。
  11. 2008年10月08日 3.通过diy自己的“程序”让自己有种成就感,
  12. 2008年10月09日 这种感觉绝对不是使用别人的工具所能言语的,
  13. 2008年10月10日 自己能写出来东西就是对自己最好的证明。
  14. 2008年10月11日 4.强大性,baidu,google里不可能搜索到能帮你解决掉所有问题的程序,
  15. 2008年10月12日 如果你不会写那些.exe程序,
  16. 2008年10月13日 那么你要完成你的目标可能就要花些银子让一些软件工作室帮你写咯。
  17. 2008年10月14日 其实决大部分系统的问题,.bat都可以轻松的帮你解决掉了。
  18. 2008年10月15日 说了这么多,到底为什么要学习批处理就是很简单的一句话:
  19. 2008年10月16日 程序是写出来满足绝大部分人的,而批处理是满足我们自己的。
  20. 2008年10月17日 每个拥有计算机和懂计算机的人都应该学习批处理。
  21. 2008年10月18日 因为世界上任何一个人都能通过简单的学习掌握批处理这门“编程语言”
复制代码

[ 本帖最后由 随风 于 2008-10-18 22:33 编辑 ]
技术问题请到论坛发帖求助!

2008-11-5号  23:18分左右测试的,
CPU :AMD 双核3800+
内存:2G DDR2

估计剩下的就和操作系统有关了。(我先前用计算π 的软件弄的机器很卡。)
应该和内存没什么关系了吧?
顺便新手来报道下,各位 午夜好。
[attach]1494[/attach]

TOP

TOP

我512M内存,1.6G双核CPU,机器配置也不怎么样。
测试最长的耗时时间正好是8秒。
这次测试结果:
心绪平和,眼藏静谧。

TOP

看代码真是累,若想完全看懂各位的代码太需要时间了。
略看了一下,发现大家都忽略了一个问题,就是代码中for循环时你们都用了 call  命令
5万行,即使只运行10分之一次,效率也是会被明显拖慢的。
在庞大的数据面前,即使是 set str=!str:~-2! 这样的语句都会对效率有一定影响。
另外:pusofalse 测试真的是7秒吗?
    我测试最好的都是 13 秒,难道真的和电脑有这么大的关系?
    各位测试的结果也贴出来看看好吗/?

[ 本帖最后由 随风 于 2008-10-20 17:58 编辑 ]
技术问题请到论坛发帖求助!

TOP

简直无敌了,测试随风兄的代码:
心绪平和,眼藏静谧。

TOP

::递加日期,以处理5万行的文本为例
::本机测试   耗时: 0 小时 0 分钟 14 秒 72 毫秒
::这次测试怎么都要14秒。。郁闷!难道是电脑不同的原因?
代码效率关键是,for 内部运行的命令越少越好。
:
  1. @echo off&setlocal enabledelayedexpansion
  2. set ttime=%time%&set wjm=ab cd.txt
  3. for /f "tokens=2 delims=:" %%a in ('find /v /c "" "%wjm%"') do set /a tian=%%a-1
  4. call :Date2Day "%date:~0,10%" %tian% sy sm sd
  5. echo  %tian% 天前的日期是:%sy%年%sm%月%sd%日
  6. set /a sm+=100,sd+=100,n=100,yue113=131
  7. for %%a in (31 28 31 30 31 30 31 31 30 31 30 31) do set /a n+=1&set /a yue!n!=1%%a
  8. set /a yue102="^!(sy%%4)&^!(^!(sy%%100))|^!(sy%%400)+128",py=yue!sm!
  9. echo.1>nul 3>c.txt
  10. for /f "usebackq delims=" %%a in ("%wjm%") do (
  11.    echo !sy!年!sm:~-2!月!sd:~-2!日 %%a
  12.    set /a sd+=1
  13.    if !sd! gtr !py! (
  14.      set /a sd=101,sm+=1&set /a py=yue!sm!&echo.
  15.      if !sm! gtr 112 (
  16.         set /a sy+=1,sm=101,yue102="^!(sy%%4)&^!(^!(sy%%100))|^!(sy%%400)+128"
  17. )))
  18. echo.1>nul 4>con
  19. call :time0 "%ttime%" "%time%" ok
  20. echo  耗时: %ok%&title ok
  21. echo.&pause
  22. start notepad "c.txt"&exit  
  23. :Date2Day 获取指定天数的日期 (封装)
  24. setlocal&rem by Will Sort @cn-dos
  25. for /f "tokens=1-3 delims=/-, " %%a in ('echo/%~1') do (
  26. set /a yy=%%a,mm=100%%b%%100,dd=100%%c%%100)
  27. set /a z=14-mm,z/=12,y=yy+4800-z,m=mm+12*z-3,j=153*m+2
  28. set /a j=j/5+dd+y*365+y/4-y/100+y/400-2472633
  29. set /a i=j-%~2,a=i+2472632,b=4*a+3,b/=146097,c=-b*146097,c/=4,c+=a
  30. set /a d=4*c+3,d/=1461,e=-1461*d,e/=4,e+=c,m=5*e+2,m/=153,dd=153*m+2,dd/=5
  31. set /a dd=-dd+e+1,mm=-m/10,mm*=12,mm+=m+3,yy=b*100+d-4800+m/10
  32. endlocal&set %3=%yy%&set %4=%mm%&set %5=%dd%&goto :EOF
  33. :time0  计算批处理运行时间(封装)
  34. setlocal&set /a n=0&rem by 随风 @bbs.bathome.net
  35. for /f "tokens=1-8 delims=.: " %%a in ("%~1:%~2") do (
  36. set /a n+=10%%a%%100*360000+10%%b%%100*6000+10%%c%%100*100+10%%d%%100
  37. set /a n-=10%%e%%100*360000+10%%f%%100*6000+10%%g%%100*100+10%%h%%100)
  38. set /a s=n/360000,n=n%%360000,f=n/6000,n=n%%6000,m=n/100,n=n%%100
  39. set "ok=%s% 小时 %f% 分钟 %m% 秒 %n% 毫秒"
  40. endlocal&set "%~3=%ok:-=%"&goto :eof
复制代码

[ 本帖最后由 随风 于 2008-10-20 17:04 编辑 ]
1

评分人数

    • terse: 精彩PB + 5 技术 + 1
技术问题请到论坛发帖求助!

TOP

  1. @echo off&setlocal enabledelayedexpansion
  2. cd.>c.txt
  3. echo %time%
  4. for %%a in (1 3 5 7 8 10 12) do set _%%a=31
  5. for %%a in (4 6 9 11) do set _%%a=30
  6. for /f "tokens=1-3 delims=- " %%a in ("%date%") do set/a "Year=%%a,Month=100%%b%%100,Day=100%%c%%100+1"
  7. for /f "delims=:" %%a in ('findstr /n /v $ "ab cd.txt"') do set /a "Line=%%a,Feb=28+^!(year%%4)"
  8. set "Monthes=1#31 2#%Feb% 3#31 4#30 5#31 6#30 7#31 8#31 9#30 10#31 11#30 12#31"
  9. for %%i in (%Monthes%) do for /f "tokens=1,2 delims=#" %%a in ("%%i") do if %%a leq %Month% set /a DayCount+=%%b
  10. for /f "tokens=%month%" %%a in ("%Monthes%") do for /f "tokens=1,2 delims=#" %%i in ("%%a") do set/a DayCount-=%%j-Day
  11. set /a LineTemp=Line-DayCount
  12. :loop
  13. set/a "LineTemp-=365+(^!(year%%4)&^!(^!(year%%100))|^!(year%%400)),Year-=1"
  14. if %LineTemp% geq 365 goto loop
  15. set/a "Year-=1,Month=12,Feb=28+^!(Year%%4)"
  16. :loop1
  17. if %LineTemp% gtr !_%Month%! (
  18.    for /f "tokens=%Month%" %%a in ("1#31 2#%Feb% 3#31 4#30 5#31 6#30 7#31 8#31 9#30 10#31 11#30 12#31") do (
  19.         for /f "tokens=1,2 delims=#" %%i in ("%%a") do set/a LineTemp-=%%j
  20.         set/a month-=1&goto loop1
  21. ))
  22. set /a Day=_%Month%-LineTemp
  23. for /f "usebackq delims=" %%a in ("ab cd.txt") do (
  24.       if !Month! lss 10 (set "Mon=0!Month!") else (set "Mon=!Month!")
  25.       if !Day! lss 10 (set "Da=0!Day!") else (set "Da=!Day!")
  26.       echo !Year!年!Mon!月!Da!日 %%a
  27.       set/a Day+=1
  28.       if !Day! GTR 28 CALL :MonitorMonthCount
  29. )>>c.txt
  30. echo %time%
  31. pause>nul&exit/b
  32. :MonitorMonthCount
  33. if %day% gtr !_%month%! set/a "day=1,month+=1"&echo.
  34. if !month! equ 13 set /a "month=1,year+=1,_2=28+(^!(year%%4)&^!(^!(year%%100)) | ^!(year%%400))"
复制代码
钻了一个空子,用findstr /n /v $ "ab cd.txt"来计算行数,当然最末行不能是空行。
心绪平和,眼藏静谧。

TOP

下面是我对自己16楼代码的测试结果:

但13秒多的速度,确实让人期待。。。
***共同提高***

TOP

原帖由 随风 于 2008-10-20 15:09 发表
呵呵,对效率的考验。。
各位都出了精彩的代码了。
暂时没时间细看代码,下回去慢慢看。。。
初步做了下测试。


16楼 batman 耗时 0 小时 1 分钟 5 秒 31 毫秒

14楼 rat 耗时 0 小时 0 分钟 57 秒 40 毫秒 ...


13秒的处理 真高效
说实话 我想尽办法也没有让代码的效率的提高
我想我的以年递减 在确定日期方面一个也快的了
就是递加和判断方面  我想是少不了一条一条判断的
期待 随风兄的精彩代码

TOP

呵呵,对效率的考验。。
各位都出了精彩的代码了。
暂时没时间细看代码,下回去慢慢看。。。
初步做了下测试。


16楼 batman 耗时 0 小时 1 分钟 5 秒 31 毫秒

14楼 rat 耗时 0 小时 0 分钟 57 秒 40 毫秒

12楼 terse 耗时 0 小时 1 分钟 7 秒 75 毫秒

本人目前的代码 耗时: 0 小时 0 分钟 13 秒 72 毫秒
代码在U盘,下次发出来。

其实思路很简单,先获取总行数,并得到N 天前的日期。再逐日递加日期。
技术问题请到论坛发帖求助!

TOP

终于将效率问题解决了,但代码确实难读了。。。
说明一下:先计算出文本的总行数,然后用渐近法计算出第一个日期(先算年再算月和日)
,然后再用for在按行读取数据时进行日期的累加和输出到新文本。
  1. @echo off&setlocal enabledelayedexpansion
  2. set "t=%time%"&echo.>c.txt
  3. rem 提出当前的年月日数值
  4. set /a year=%date:~,4%,month=1%date:~5,2%%%100,day=1%date:~8,2%%%100
  5. rem 设置变量
  6. for %%i in (31 29 31 30 31 30 31 31 30 31 30 31) do (
  7.     set /a num+=1&set "_!num!=%%i"
  8.     set "code1=!code1! %%i"&set "code2=!code2! !num!#%%i"
  9. )
  10. rem 获取文本总行数
  11. for /f "usebackq delims=" %%i in ("ab cd.txt") do set /a n+=1
  12. rem 计算并减去本年已过的天数
  13. set /a n=n-day
  14. for %%a in (%code1%) do (
  15.     if "!m!" neq "%month%" (
  16.        set /a n-=%%a,m+=1
  17.        ) else (
  18.        goto lp1
  19.    )
  20. )
  21. :lp1
  22. rem 计算初始年份
  23. set /a year-=1,n-=365
  24. set /a a=year%%4,b=year%%100,c=year%%400,yun=28,_2=28
  25. if %b% equ 0 (
  26.    if %c% equ 0 set /a n-=1,yun+=1,_2+=1
  27.    ) else (
  28.    if %a% equ 0 set /a n-=1,yun+=1,_2+=1
  29. )
  30. if %n% geq 0 goto lp1
  31. set "code1=!code1:29=%yun%!"&set "code2=!code2:29=%yun%!"
  32. rem 计算初始月份和日期
  33. for %%a in (%code2%) do (
  34.     for /f "tokens=1,2 delims=#" %%i in ("%%a") do (
  35.         set /a n+=%%j
  36.         if !n! geq 0 set /a month=%%i-1,day=%%j-n&goto next
  37.     )
  38. )
  39. :next
  40. rem 核心代码部分,读取文本内容并递加日期,输出到新文本
  41. for /f "usebackq delims=" %%i in ("ab cd.txt") do (
  42.     set /a n=day-_!month!
  43.     if !n! gtr 0 call :lp2
  44.     if !month! geq 10 (
  45.        if !day! geq 10 (
  46.           echo !year!年!month!月!day!日 %%i>>c.txt
  47.           ) else (
  48.           echo !year!年!month!月0!day!日 %%i>>c.txt
  49.        )
  50.        ) else (
  51.        if !day! geq 10 (
  52.           echo !year!年0!month!月!day!日 %%i>>c.txt
  53.           ) else (
  54.           echo !year!年0!month!月0!day!日 %%i>>c.txt
  55.        )
  56.     )
  57.     set /a day+=1
  58. )
  59. echo 开始时间:%t%
  60. echo 结束时间:%time%
  61. pause>nul&goto :eof
  62. :lp2
  63. rem 子程序:跨月、跨年的计算和判断
  64. echo.>>c.txt
  65. set /a month+=1,day=1
  66. if %month% equ 13 (
  67.    set /a year+=1,month=1,a=year%%4,b=year%%100,c=year%%400,_2=28
  68.    if !b! equ 0 (
  69.       if !c! equ 0 set "_2=29"
  70.       ) else (
  71.       if !a! equ 0 set "_2=29"
  72.    )
  73. )
复制代码

[ 本帖最后由 batman 于 2008-10-20 03:40 编辑 ]
***共同提高***

TOP

原帖由 batman 于 2008-10-19 19:40 发表
看了这段代码,人都要晕了。。。。我也想过用这种方法,但这样效率肯定是上不去的,因
为这样要进行100000次日期计算,其中还要进行很多次的判断,但另一种平常好用的设置
变量法实践中效率更低(变量数量太大了) ...

其实没有进行100000次日期计算  假设50000行 就是50000次运算啊  其中判断少不了的

TOP

  1. @echo %time%
  2. @echo off & setlocal enabledelayedexpansion
  3. set sOldFile="ab cd.txt"
  4. set sNewFile="c.txt"
  5. for %%a in (31 28 31 30 31 30 31 31 30 31 30 31) do set /a i += 1 && set iM!i!=%%a
  6. for /f "tokens=1-3 delims=-" %%a in ("%date%") do set iThisYear=%%a & set iThisMonth=%%b & set iThisDay=%%c
  7. set /a iLeapYearCount = (iThisYear - 1) / 4 - (iThisYear - 1) / 100 + (iThisYear - 1) / 400
  8. call :GetFebDayCount %iThisYear% iM2
  9. for /l %%a in (1, 1, %iThisMonth%) do if %%a lss %iThisMonth% set /a iThisMonthToDayCount += iM%%a
  10. set /a iAllDayCount = 365 * (iThisYear - 1) + iLeapYearCount + iThisMonthToDayCount + iThisDay
  11. for /f "usebackq delims=" %%a in (%sOldFile%) do set /a iDayDiff += 1
  12. set /a iFirstDayCount = iAllDayCount - (iDayDiff - 1)
  13. set /a iTempYear = iFirstDayCount / 365 - 1
  14. :GetDate
  15. set /a iTempLeapCount = iTempYear / 4 - iTempYear / 100 + iTempYear / 400
  16. set /a iTempDayCount = iFirstDayCount - 365 * iTempYear - iTempLeapCount
  17. if %iTempDayCount% lss 0 set /a iTempYear -= 1 && goto :GetDate
  18. if %iTempDayCount% equ 0 set /a iYear = iTempYear, iMonth = 12, iDay = 31 && goto :WriteText
  19. set /a iYear = iTempYear + 1
  20. call :GetFebDayCount %iYear% iM2
  21. for /l %%a in (1, 1, 12) do (
  22. set /a iTempDayCount -= iM%%a
  23. if !iTempDayCount! leq 0 set /a iMonth = %%a, iDay = iM%%a + iTempDayCount, iTempDay = iM%%a && goto :WriteText
  24. )
  25. :WriteText
  26. cd.>%sNewFile%
  27. for /f "usebackq delims=" %%a in (%sOldFile%) do (
  28. if !iMonth! lss 10 (set sMonth=0!iMonth!) else (set sMonth=!iMonth!)
  29. if !iDay! lss 10 (set sDay=0!iDay!) else (set sDay=!iDay!)
  30. >>%sNewFile% echo !iYear!年!sMonth!月!sDay!日 %%a
  31. if !iDay! lss !iTempDay! (
  32. set /a iDay += 1
  33. ) else (
  34. >>%sNewFile% echo.
  35. if !iMonth! lss 12 (
  36. set /a iMonth += 1, iDay = 1
  37. ) else (
  38. set /a iYear += 1, iMonth = 1, iDay = 1
  39. call :GetFebDayCount !iYear! iM2
  40. )
  41. set /a iTempDay = iM!iMonth!
  42. )
  43. )
  44. echo %time%
  45. pause
  46. exit /b
  47. :GetFebDayCount
  48. for %%a in (4 100 400) do set /a r%%a=%1%%%%a
  49. set %2=28
  50. if %r400%==0 (set %2=29) else (if %r4%==0 if not %r100%==0 set %2=29)
复制代码

[ 本帖最后由 rat 于 2008-10-20 16:55 编辑 ]
2

评分人数

    • pusofalse: 果真高人。PB + 15 技术 + 1
    • batman: 高人,建议加入我们的版主行列PB + 15 技术 + 1

TOP

看了这段代码,人都要晕了。。。。我也想过用这种方法,但这样效率肯定是上不去的,因
为这样要进行100000次日期计算,其中还要进行很多次的判断,但另一种平常好用的设置
变量法实践中效率更低(变量数量太大了),所以一直未能达到小楼兄的要求。。。
用kip的方法可以将文本未行变成首行,但输出就整个是反过来的,即当前日期和未行成了第
一行,再用一次skip就可以按要求输出了,但这样既显得罗索,效率也达不到一分左右完成
这一要求,同时可能还要生成一次临时文件。。。
期待小楼兄的答案。。。
***共同提高***

TOP

返回列表