[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖
如果文本行都在80个字符以内的话,可用以下这种高效的办法:
  1. @echo off&setlocal enabledelayedexpansion
  2. for /l %%a in (1,1,80) do set "k=!k!0"
  3. for /f "delims=" %%a in (a.txt) do (
  4.     set "str=%%a"&set "str=%k% !str: =!"
  5.     set "str=!str:~-80!"&set /a n+=1
  6.     for /f %%b in ("!str!") do set "_%%b=%%a"&set ".%%a=!n!"
  7. )
  8. for /f "tokens=1,2 delims==_" %%a in ('set _') do (
  9.     set "str=%%a"&set "var=%%b"
  10.     for /l %%i in (1,1,80) do if "!str:~%%i!" equ "" set /a num=79-%%i&goto next
  11. )
  12. :next
  13. echo 字符数是多的是!.%var%!行,共有%num%个字符。
  14. pause>nul
复制代码
***共同提高***

TOP

折半法 可处理每行最多 8189 个字符,效率不错。
  1. @echo off&setlocal enabledelayedexpansion
  2. ::@随风 @bbs.bathome.net @2009-04-18
  3. for /f "delims=" %%a in (a.txt) do (
  4.    set /a sun+=1,n=8189*2,max=1
  5.    set s=%%a&set s=!s: =!&set "var="
  6.    for /l %%a in (1 1 14) do (
  7.       if defined var set /a n=var
  8.       set /a n/=2
  9.       for %%i in (!n!) do (
  10.          if "!s:~%%i,1!"=="" (set /a var=n) else (
  11.             set s=!s:~%%i!&set /a max+=%%i,var-=%%i
  12.    )))  
  13.    if !h! lss !max! set /a num=sun,h=max
  14. )
  15. echo 字符数最多的行为:!num!
  16. echo 字符数为:!h!
  17. pause
复制代码

[ 本帖最后由 随风 于 2009-4-18 17:01 编辑 ]
技术问题请到论坛发帖求助!

TOP

取长补短为提速

  1. @echo off&setlocal enabledelayedexpansion
  2. set m=0
  3. for /f "delims=" %%a in (a.txt) do (
  4.     set "str=%%a"&set "str=!str: =!0"
  5.     for %%b in (!m!) do (if "!str:~%%b,1!" neq "" call :sub "%%a")
  6. )
  7. echo 字符数是多的是%var%行,共有%m%个字符。
  8. pause
  9. goto :eof
  10. :sub
  11. set/a en=m+40
  12. for /l %%a in (!m!,1,!en!) do (
  13. if "!str:~%%a,1!" equ "" (
  14.   set/a n=%%a-1
  15.   if !m! lss !n! set/a m=!n!,n=0&set "var=%~1"
  16.   goto :eof
  17. )
  18. )
  19. set/a m=en
  20. goto :sub
复制代码

TOP

请留意中间的输出,此法应该是最高效了吧?
  1. @echo off&setlocal enabledelayedexpansion
  2. set m=1
  3. for /f "delims=" %%a in (a.txt) do (
  4.     set "str=%%a"&set "str=!str: =!0"
  5.     for %%b in (!m!) do (if "!str:~%%b,1!" neq "" call :sub "%%a")
  6. )
  7. set /a m-=1
  8. echo 字符数是多的是%var%行,共有%m%个字符。
  9. pause
  10. goto :eof
  11. :sub
  12. set/a en=m+40
  13. for /l %%a in (!m!,1,!en!) do (
  14.         if "!str:~%%a,1!" equ "" (
  15.                 echo 较多: %~1
  16.         set/a m=%%a&set "var=%~1"&goto :eof)
  17. )
  18. set/a m=en
  19. goto :sub
复制代码
1

评分人数

TOP

19楼思路非常巧妙,从少到多,只判断字符数多的行,不判断少的行。省略了很多无用的判断。
技术问题请到论坛发帖求助!

TOP

看来从心动到行动
还有很长的距离啊
  1. ::  GetMaxCharText.cmd - 找出字符最多的文本行
  2. ::  qzwqzw - 2010-01-05
  3. ::
  4. ::  基本构思:
  5. ::      将原文本每行尾部加足够的一定数量的空格,在文本右侧形成一个不等齐空格区域
  6. ::      原文本行越长,其后的空格区域就越长,然后用sort /+n 仅对空格区域进行排序
  7. ::      因为区域内都是空格,则排序的依据就是空格的长度,也就是原行文本的长度
  8. ::
  9. @echo off & setlocal EnableDelayedExpansion
  10. set maxLineLen=80
  11. set infile=%~sf0
  12. for /l %%i in (1,1,%maxLineLen%) do set zone= !zone!
  13. :: findstr 会忽略空行和仅含空格的行,但显示行号会跨过这些行,这是我们需要的特性
  14. :: 将行号与行文本分别处理,是因为不对齐行号会影响行文本长度的判断
  15. (for /f "tokens=1* delims=:" %%l in ('findstr /n /r /c:"[^ ]"  %infile%') do (
  16.     set LineNo=         %%l
  17.     set LineNo=!LineNo:~-10!
  18.     set Line=%%m
  19.     set Line=!Line: =!
  20.     echo.!LineNo!:!Line!!zone!
  21. ))>%temp%\%~sn0~1.t~1
  22. sort /r /+%maxLineLen% %temp%\%~sn0.t~1 > %temp%\%~sn0.t~2
  23. set/p maxLine=< %temp%\%~sn0.t~2 >nul
  24. ::  已找到最多字符的行,以下是提取行号和原行文本,行长度因未要求而忽略
  25. for /f "delims=: " %%i in ("%maxline%") do set maxLineIdx=%%i
  26. ::  使用find而不是findstr,是因为find够用够简单
  27. set seekLine=find /v /n "" ^^^<%infile%^^^|find "[%maxLineIdx%]"
  28. echo.字符最多的行第 %maxLineIdx% 行,内容为:
  29. for /f "tokens=1* delims=[]" %%l in ('%seekLine%') do echo.%%m
  30. for %%f in (%temp%\%~sn0.t*) do del %%f
复制代码

[ 本帖最后由 qzwqzw 于 2010-1-5 10:46 编辑 ]

TOP

  1. @echo off&setlocal enabledelayedexpansion
  2. for /f "delims=" %%a in (a.txt) do (
  3.      set /a t+=1
  4.      set i=%%a
  5.      set y!t!=!i!
  6.      set i=!i: =!
  7.      call:x !i!
  8.      set /a n!t!=!num!
  9. )
  10. for /l %%b in (1 1 !t!) do (
  11. if !n%%b! lss !number! (
  12. set /a n%%b=number
  13. set y%%b=!str!
  14. )
  15. set /a number=n%%b
  16. set str=!y%%b!
  17. cls
  18. echo 字符数最多的行是:!y%%b!共有字符:!n%%b! 个
  19. )
  20. pause>nul&exit
  21. :x
  22.     set i=%1
  23.     set num=
  24. :loop
  25.      set i=!i:~1!
  26.      set /a num+=1
  27.      if "!i!"==""  ( echo abc >nul
  28.      )  else ( goto:loop)
复制代码

[ 本帖最后由 vincentzhou 于 2011-1-9 13:27 编辑 ]
only the strong survive!

TOP

本帖最后由 zm900612 于 2011-5-16 13:28 编辑

来一个以sort为核心的全新思路:
  1. @echo off&setlocal enabledelayedexpansion
  2. set /a $=11,n=4096
  3. for /l %%a in (-2 1) do set $=!$!!$!!$!!$!
  4. (copy a.txt %$%$&findstr .* %$%?>$
  5. for %%a in (2048 1024 512 256 128 64 32 16 8 4 2 1) do sort /+100 /rec !n! $&&set /a n-=%%a,h=n-130||set /a n+=%%a)>nul 2>nul
  6. for /f "delims=" %%a in ('sort /+%h% a.txt') do set long=%%a
  7. echo !long!
  8. del /f /q *$&pause
复制代码
看到这题又浮了上来,想起正好能用上前阵子开发的用sort命令判断文件中最长行字符数的代码,于是把代码改造了下...
这种以外部命令为主的算法计算小文件时不快,但是在计算大文件时将有速度优势。

TOP

23# zm900612
代码过于求奇求异
又缺乏必要的注释
是在考验读者的耐心
我不欣赏这样的风格
天的白色影子

TOP

本帖最后由 zm900612 于 2011-5-16 13:37 编辑
23# zm900612
代码过于求奇求异
又缺乏必要的注释
是在考验读者的耐心
我不欣赏这样的风格
qzwqzw 发表于 2011-5-15 21:21

求奇求异倒不是刻意为之,只是平时喜欢发掘命令的新鲜用法,积累多了,在特定的场合自然会联想到,如果别人不了解我的积累,肯定不容易一下就看明白思路是什么...至于注释,确实没有养成这个代码习惯,以后会注意。

附上对23楼代码的解读:
首先要先说明一下,核心代码来自于前不久研究sort的rec开关时想到的用法:
  1. @echo off&setlocal enabledelayedexpansion
  2. set n=32768
  3. (for %%a in (16384 8192 4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do sort /+100 /rec !n! 1.txt&&set /a n-=%%a||set /a n+=%%a)>nul 2>nul
  4. ::很像plp兄曾转发过的折半回溯法求字符长度的函数吧?是的,这里就是对那个思路的改造,只不过我是利用sort /rec超过最长行字数时会出错的特性来进行运算的。
  5. echo 最长行有%n%个字符
  6. pause
复制代码
但是当时这个代码有个缺点,就是当最长行的字数低于128时,sort /rec的值无论设为多少都是不会出错的。
好在曾经拜读过用findstr实现多色显示的代码,从中获取了灵感,于是23楼代码中就用同样的原理为a.txt中每行补齐128个字符的前缀,这样就绕过了原先的限制
23楼代码为了简化而写得比较晦涩,现在翻译成大众版:
  1. @echo off&setlocal enabledelayedexpansion
  2. set /a tmp=11,n=4096
  3. ::此处的tmp是用于补位的,设成任意两个字符都行,为了压缩代码,把它设成十位数
  4. for /l %%a in (1 1 3) do set tmp=!tmp!!tmp!!tmp!!tmp!
  5. ::将tmp补足128位
  6. copy>nul a.txt %tmp:~2%$
  7. ::将a.txt保存到一个文件名长度为127个字符的临时文件中
  8. findstr .* %tmp:~2%?>$
  9. ::用findstr命令配合通配符实现补位,127个字符长的文件名加上“:”号,刚好128个字符,将结果输出到临时文件中
  10. for %%a in (2048 1024 512 256 128 64 32 16 8 4 2 1) do (
  11.    sort /+100 /rec !n! $&&set /a n-=%%a,h=n-128||set /a n+=%%a
  12. )>nul 2>nul
  13. ::用sort /rec判断该临时文件最长行的长度
  14. for /f "delims=" %%a in ('sort /+%h% a.txt') do set long=%%a
  15. ::因为知道了最长行的长度,所以可以直接用sort /+n来精确排序,通过for命令,很容易获得最后一行的内容(用set /p也可以,但是考虑到变量长度,还是用for保险,当然用findstr取指定行也是一个不错的选择)。
  16. echo !long!
  17. ::不解释
  18. del /f /q *$
  19. ::删除临时文件,销赃
  20. pause
复制代码
1

评分人数

TOP

23楼的代码中,至少用了三种比较偏门的技巧,所以看起来就显得奇异一些...

TOP

代码看着顺畅多了
不需要实际测试与断点跟踪也能明白思路
给两个建议:
1、set /a h=n-128移到for之外
2、取最长行用for/f+sort又成为线性算法
for/f需要完整遍历整个文件才能取得最长行
与你通篇的算法思路相左
不如仍然用set/p+sort /r
至于变量长度这与for/f中的set long有不同吗?
天的白色影子

TOP

另外发现一个小问题
悄悄的告诉你
楼主的题目要求是获取不包含空格的字符数最多行
天的白色影子

TOP

代码看着顺畅多了
不需要实际测试与断点跟踪也能明白思路
给两个建议:
1、set /a h=n-128移到for之外
2、取最长行用for/f+sort又成为线性算法
for/f需要完整遍历整个文件才能取得最长行
与你通篇的算法思路相 ...
qzwqzw 发表于 2011-5-16 15:28


1、这个,如果没记错的话,一个set /a的用时好像是set /a内部二十几个算式的计算耗时,而此处实际上只需要计算12次,所以我感觉这个算式还是能联用就联用
2、最初确实忽略了思路的连贯性,刚刚解释代码的时候也想到这一点,所以加了句用“findstr也是不错的选择”
关于变量长度,set /p与set的区别在于set "str=#@#¥#……&"时变量长度上限8192字节,而set /p str=请输入#@#¥#……&时则只能定义1024字节,这与前面折半回溯所支持的字符长度相悖,所以放弃了set /p。
改进的思路是:
  1. endlocal
  2. for /f "tokens=1* delims=:" %%a in ('findstr /n a.txt^|findstr 1:') do set "long=%%b"
  3. ...
复制代码
3、没看到楼主要求是不含空格,不过好像在谁的代码中看到了"findstr /o"...
我的代码习惯可能比较明显,要么大量使用外部命令,要么一堆for嵌套+set,减少call和goto。如果碰到大文件,外部命令优势明显,但是若要进行更精细的筛选,那还是只好老老实实用for了...

TOP

set /a的问题不是在效率上
而是在逻辑上
因为你在set /a n+=%%a时并没有计算h
那么如果set /a n-=%%a在特定条件下没有运行一次
那么h的取值为空
或者set /a n-=%%a最后一次没有运行
那么h的取值会差1

set/p的字符长度限制确实是忘记了
记忆力确实越来越差了
扩展测试了一下
windows记事本也有每行1024字符的限制
find命令同样也有

不过你的改进思路有些问题
似乎忘记了sort /r
天的白色影子

TOP

返回列表