曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 3822|回复: 1
打印 上一主题 下一主题

[实例.其它] 逐行显示文本,以及等号输出不换行的另类处理方法

[复制链接]

716

主题

734

帖子

2946

积分

超级版主

Rank: 9Rank: 9Rank: 9

积分
2946
跳转到指定楼层
楼主
发表于 2014-6-4 16:58:30 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
看到一个逐行显示的批处理代码:
  1. for /f "delims= eol=" %%i in ('type %1') do (
  2.     set "str=%%i"
  3.     call set "str=%%str:"= %%"
  4.     call :pickup
  5. )
  6. pause
  7. goto :eof

  8. :pickup
  9. ping -n 1 127.1>nul
  10. if "%str:~0,1%"=="=" set "str=〓%str:~1%"
  11. set /p "=%str:~0,1%"<nul
  12. set "str=%str:~1%"
  13. if defined str goto pickup
  14. echo.&echo.
  15. goto :eof
复制代码

它的作用是逐行显示一个文本,就是模拟每一行的快速向前推进输出,而不是一下子整行的输出。

先说明一下代码里面的一些语句:

call set "str=%%str:"= %%"
这行语句是将 %%str:"=%% 赋值给 str ,这实际上是 set 的一种增强型表达式,即将“空格”代替文本行中的双引号(具体参考 set /?)。如果你疑问为什么用这么多百分号,那么请参考 call set 的说明《call set 与 变量延迟》。


if "%str:~0,1%"=="=" set "str=〓%str:~1%"
这一条语句的目的是将行中的 = 号换成 〓 ,为什么这么做?
这是因为,逐行推进式的显示,会涉及到不换行的输出,这需要用 set /p "=xxxx"<nul 这种做法,如果直接用 echo 来做,这就会导致换行,而批处理里的 echo 功能却弱于 linux shell 中的 echo,人家可以直接一个 -n 选项不换行。若是用 set /p 来输出等号,似乎找不到什么可行的办法,因为等号在批处理里是个特殊用法的符号,即使你用 ^ 转义字符也不行。那我们如果不想输出这个 〓 符号,而是直接输出原汁原味的 = 符号那该怎么办?直接用批处理,我找不到更加直接的做法,但想到了一个另类的做法:= 符号用一个可执行程序来输出,比如 C 代码就只有一句 printf ("="); 即可。将该比 hello world 还要更小的 C 程序复制到如 D:\ 的根目录下,那么可以有如下代码:
  1. @echo off
  2. for /f "delims= eol=" %%i in ('type %1') do (
  3.     set str=%%i
  4.     ::call set "str=%%str:"= %%"
  5.     call :pickup
  6. )
  7. goto :eof

  8. :pickup
  9. ping -n 1 127.1>nul
  10. if "%str:~0,1%"=="=" set "str=〓%str:~1%"&D:\Project1.exe>sss.txt&type sss.txt&&set str=%str:~1%&del

  11. sss.txt&goto pickup
  12. set /p "=%str:~0,1%"<nul
  13. set str=%str:~1%
  14. if defined str goto pickup
  15. echo.&echo.
  16. goto :eof
复制代码

上面代码中,project1.exe 就是在命令行中打印 '=' 符号的程序,我们执行这个程序并将输出重定向到一个名为 sss.txt 的临时文件中,然后在用 type 来将其打印,弄完之后再 del 掉该临时文件。需要注意的是,不能 echo 一个 = 符号到一个文本中,那样仍然包含一个换行,而 C 程序是可以控制不包含换行符的输出。

至于除了等号之外的其它特殊符号,该程序是可以处理的。

716

主题

734

帖子

2946

积分

超级版主

Rank: 9Rank: 9Rank: 9

积分
2946
沙发
 楼主| 发表于 2014-6-4 18:29:37 | 只看该作者
逐行显示文本版本2,代码如下:
  1. @echo off
  2. for /f "delims= eol=" %%i in ('findstr /n .* %1') do (
  3.     set "str=%%i"
  4.     call set "str=%%str:"= %%"
  5.     call set "str=%%str:*:=%%"
  6.     call :pickup
  7. )
  8. echo.
  9. pause
  10. goto :eof

  11. :pickup
  12. if not defined str echo.&goto :eof
  13. if "%str:~0,1%"=="=" set "str=〓%str:~1%"
  14. set /p "=%str:~0,1%"<nul
  15. ping -n 1 127.1>nul
  16. set "str=%str:~1%"
  17. if defined str goto pickup
  18. echo.
  19. goto :eof
复制代码


该版本代码主要是增加了对空行也能照样输出的功能,这和上面的代码每次都强制输出一个空行是不同的。此外,该版本不支持 unicode 的处理。

findstr /n .* %1
for 循环里的这条语句给每行添加行号,其形式为 1:aaaaaaaa, 2:bbbbbbb 。

call set "str=%%str:"= %%"
该条语句主要是第文本行中的双引号的过滤。

call set "str=%%str:*:=%%"
该语句将 1: , 2: 这些行号去掉,这看上去似乎没什么意义,因为添加了行号,又将其去掉,貌似是多此一举。但是看到 :pickup 里 if not defined str echo.&goto :eof 这条语句后,就知道它主要是针对空行所设置的。因为如果是一个空行的话,那么在去掉其行号后,str 的值为空,这样用 if not defined 来测试就会成立,即认为 str 是“not defined”的。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-6-17 21:33 , Processed in 0.077882 second(s), 21 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表