Board logo

标题: [文本处理] 【练习】批处理显示文本中8字节的行 [打印本页]

作者: 随风    时间: 2009-6-10 17:19     标题: 【练习】批处理显示文本中8字节的行

在百度贴吧看到一题,出给大家练练手。
那儿有一仙说他们老大不加思索就作出来了,(本人足足想了10分钟才有完整思路)实在对这位老大佩服的很,可惜未见到代码 (^_^)
题:
要求显示a.txt中8字节的行,注意有特殊字符 ^%&<!>等。
增加要求为:不创建临时文件,不使用第三方工具。
注意:说的是字节而不是字符,需考虑到多种情况,比如冒号、分号开头的行。。。




.
作者: zqz0012005    时间: 2009-6-10 17:37

我首先想到的思路是:for /f 解析 findstr /o 做减法
作者: batman    时间: 2009-6-10 17:45

小水一个:不创建临时文件就确实加大了难度了,呵呵,看看大家的思路吧。。。
作者: netbenton    时间: 2009-6-10 19:02

抛砖引玉
  1. @echo off
  2. for /f "delims=" %%a in (%~0) do (
  3.     set str=%%a
  4.     setlocal enabledelayedexpansion
  5.     if "!str:~8!" equ "" (
  6.         for /l %%b in (0,1,7) do (
  7.                 if "!str:~%%b,1!" neq "" (
  8.                         if "!str:~%%b,1!0" gtr "z" (set/a len+=2) else (set/a len+=1)
  9.                                         rem     ^ 这个字符用小于最小全角字符的即可,这知是不是z
  10.                 )
  11.         )
  12.     )
  13.     if !len! equ 8 echo;!str!
  14.     endlocal
  15. )
  16. pause
  17. rem 后面的是例子
  18. :2345678
  19. ::批处理
  20. ::!!!!!!
  21. ::^"!!|>
  22. ::物><!%
  23. :23456789
  24. ::批处理1
  25. ::!!!!!!1
  26. ::^"!!|>1
  27. ::物><!%1
复制代码

作者: 随风    时间: 2009-6-10 19:12     标题: 回复 4楼 的帖子

先忽略8个字符以上的行,再逐字判断,不错,但若需显示的行不是8字节而是更大点的数,效率会同时降低,且未考虑分号开头的行和含全角空格的行。
先加5分,后面的继续。。。

[ 本帖最后由 随风 于 2009-6-10 19:19 编辑 ]
作者: netbenton    时间: 2009-6-10 19:28

解决分号问题了
  1. @echo off
  2. for /f "tokens=* delims=;" %%a in ('findstr /n .* %0') do (
  3.     set str=%%a
  4.     setlocal enabledelayedexpansion
  5.     set "str=!str:*:=!"
  6.     if "!str:~8!" equ "" (
  7.         for /l %%b in (0,1,7) do (
  8.                 if "!str:~%%b,1!" neq "" (
  9.                         if "!str:~%%b,1!0" gtr "z" (set/a len+=2) else (set/a len+=1)
  10.                                         rem     ^ 这个字符用小于最小全角字符的即可,这知是不是z
  11.                 )
  12.         )
  13.     )
  14.     if !len! equ 8 echo;!str!
  15.     endlocal
  16. )
  17. pause
  18. rem 后面的是例子
  19. :2345678
  20. ::批处理
  21. ::!!!!!!
  22. ::^"!!|>
  23. ::物><!%
  24. :23456789
  25. ::批处理1
  26. ::!!!!!!1
  27. ::^"!!|>1
  28. ::物><!%1
  29. ;ddddddd
复制代码

作者: 随风    时间: 2009-6-10 19:41     标题: 回复 6楼 的帖子

全角空格呢?   (^_^)
作者: zqz0012005    时间: 2009-6-10 19:51

考虑到所有特殊字符的情况后,2楼说的方法实现起来还真有点麻烦。
先来个代码简单但效率超低的方法
  1. @echo off
  2. set var2=.
  3. for /f "usebackq delims=" %%a in ("%~f0") do (
  4.     set var=%%a
  5.     set var|findstr /o ".*"|findstr /b "14:" >nul && (
  6.         setlocal enabledelayedExpansion
  7.         echo !var!
  8.         endlocal
  9.     )
  10. )
  11. pause&exit/b
  12. :2345678
  13. ^%; <!"
  14. 上面是全角空格
复制代码

作者: 随风    时间: 2009-6-10 19:56     标题: 回复 8楼 的帖子

效率是够低的,也每考虑分号开头的行 (^_^)
作者: netbenton    时间: 2009-6-10 20:25

高效的,可处理绝大部分字符
  1. @echo off
  2. for /f "tokens=*" %%a in ('^(type %0^&echo.^)^|findstr /o .*') do (
  3.     set str=%%a
  4.     setlocal enabledelayedexpansion
  5.     for /f "delims=:" %%b in ("!str!") do (
  6.                 set/a len=%%b-up-2
  7.                 if !len! equ 8 echo !ech!
  8.                     set "ech="
  9.                 for %%c in ("!str:*:=!") do (
  10.                         endlocal&set up=%%b&set ech=%%~c
  11.     ))
  12. )
  13. pause
  14. rem 后面的是例子
  15. :2345678
  16. ::批处理
  17. ::!!!!!!
  18. ::^"!!|>
  19. ::物><!%
  20. :23456789
  21. ::批处理1
  22. ::!!!!!!1
  23. ::^"!!|>1
  24. ::物><!%1
  25. ;ddddddd
复制代码

作者: zqz0012005    时间: 2009-6-10 20:39     标题: 回复 8楼 的帖子

2楼的方法其实不麻烦,开始没想清楚,变量还是可以保留的
  1. @echo off
  2. for /f "tokens=1* delims=:" %%a in ('findstr /n /o .* "%~f0"') do (
  3.     for /f "delims=:" %%i in ("%%b") do set m=%%i
  4.     set /a x=m-n
  5.     setlocal enabledelayedExpansion
  6.     if !x!==10 echo !var:*:=!
  7.     endlocal
  8.     set /a n=m
  9.     set var=%%b
  10. )
  11. pause&exit/b
  12. ;2345678
  13. ^%; <!"
  14. 上面是全角空格
复制代码

作者: zqz0012005    时间: 2009-6-10 20:43

晕,findstr /n 写习惯了,%%a根本没用到~~
for /f "delims=" %%a in ('findstr /o .* "%~f0"') do


方法都一样,被netbenton兄抢先了,而且考虑到了最后一行没有回车的情况。
"tokens=*"改成"delims="就兼容所有字符了。
可以用more "%~f0"|findstr /o .*更简洁点,more会在文本内容后面加额外的回车。

[ 本帖最后由 zqz0012005 于 2009-6-10 20:57 编辑 ]
作者: netbenton    时间: 2009-6-10 21:07

re zqz0012005
我正找了半天,怎么解最后一行不是空格的问题呢!
原来用more可以自动加空行呀,太好了!
完美代码如下:
  1. @echo off
  2. for /f "tokens=*" %%a in ('^(more %0 ^&echo aa^)^|findstr /o .*') do (
  3.     set str=%%a
  4.     setlocal enabledelayedexpansion
  5.     for /f "delims=:" %%b in ("!str!") do (
  6.         set/a len=%%b-up-2
  7.         if !len! equ 8 echo !ech:*:=!
  8.         endlocal&set/a up=%%b
  9.     )
  10.     set ech=%%a
  11. )
  12. pause
  13. rem 后面的是例子
  14. :2345678
  15. ::批处理
  16. ::!!!!!!
  17. ::^"!!|>
  18. ::物><!%
  19. :23456789
  20. ::批处理1
  21. ::!!!!!!1
  22. ::^"!!|>1
  23. ::物><!%1
  24. ;ddddddd
  25. ^%; <!"
复制代码

作者: 随风    时间: 2009-6-10 21:14     标题: 回复 12楼 的帖子

zqz 真是一语点醒梦中人,代码早以写好,就是解决不了最后一行没有回车的问题。老是用type
最终大家的思路都到一起来了 (^_^)
代码如下:
  1. @echo off&set /a h=0
  2. for /f "delims=" %%a in ('^(more %~s0^&echo.^)^|findstr /o .*') do (
  3.    for /f "delims=:" %%i in ("%%a") do set /a n=%%i-2-h,h=%%i
  4.    setlocal enabledelayedexpansion
  5.    if !N! equ 8 echo;【!var:*:=!】
  6.    endlocal
  7.    set "var=%%a"
  8. )
  9. pause&exit
  10. 下面是分号开头的行
  11. ;1234567
  12. 下面是8个空格
  13.         
  14. 下面是冒号开头的行
  15. ::::::::
  16. 下面是特殊字符的行
  17. %^&*<">!
  18. 下面是含全角空格的行
  19.    78
  20. 下面是全角半角混合的行
  21. 壹23肆78
  22. 下面是纯半角字符的行
  23. 12345678
复制代码

作者: zqz0012005    时间: 2009-6-10 21:21

忘了,最后还要自己加一行,以应付最后一行也是8个字节的情况。
作者: tireless    时间: 2009-6-10 22:10

z 区分不了双字节与单字节字符。

全角字符占 2 个字节,而全角的 a会小于半角的 b
作者: terse    时间: 2009-6-10 22:35

还真没想到 more 会自己加行  最后行一直困人哦  少个FOR 可行吗
  1. @echo off
  2. for /f "tokens=1* delims=:" %%i in ('"(more 1.txt&echo aa)|findstr /o ".*""') do (
  3.    set/a n=%%i-m-2
  4.    setlocal enabledelayedexpansion
  5.    if !n! equ 8 echo !var!
  6.    endlocal&set var=%%j&set/a m=%%i
  7. )
  8. pause
复制代码

作者: 随风    时间: 2009-6-10 22:52     标题: 回复 17楼 的帖子

这样会忽略冒号开头的行吧。
作者: slore    时间: 2009-6-11 01:14

1234567半

不能完全8字节分吧...汉字难道要...
作者: qq106942397    时间: 2009-6-11 23:28

测试一吓我的笨方法吧~~


@echo off
for /f "tokens=* delims=國" %%a in (总和数.txt) do (
set "q=%%a"
echo %%a>t.txt<nul
echo.>>t.txt
for /f "skip=1 tokens=1* delims=:" %%b in ('findstr /o .* t.txt') do (
if %%b==10 call set/p"=%%q%%">>总和数2.txt<nul&echo.>>总和数2.txt
)
)
del t.txt
pause
作者: qq106942397    时间: 2009-6-11 23:30

对文本大的速度不行~~现在还在想另的方法~~在群里还谈~~你又不上群里聊~~~
作者: qq106942397    时间: 2009-6-14 21:16

楼上骗子点击呀~~~
用EXE文件这也算吗???
作者: 随风    时间: 2009-6-14 21:23     标题: 回复 23楼 的帖子

看22楼的意思应该是自己编写的exe文件,这不应该说算,应该说很牛啊。
作者: keen    时间: 2009-6-14 23:05

  1. @echo off
  2. for /f "eol= delims=" %%i in ('type a.txt') do (set "str=%%i"
  3.     for /f "skip=1 delims=:" %%a in ('^(echo "%%i"^&echo;^)^|findstr /o .*') do (
  4.         set /a num=%%a-5
  5.         setlocal enabledelayedexpansion
  6.         if !num! equ 8 echo;!str!
  7.         endlocal
  8. )
  9. )
  10. pause
复制代码

作者: 随风    时间: 2009-6-23 15:43

狂汗,居然如此简单。。。
:
  1. @echo off
  2. (more a.txt&echo.)|findstr /x ........
  3. pause
复制代码

作者: zqz0012005    时间: 2009-6-23 18:05

后面的“echo.”是不必要的,more也是不必要的,直接用type也行,此时不存在最后行问题。

findstr 的正则还真是古怪。下面是javascript的正则:
  1. mshta "javascript:alert( '12345678\r\n一二三四'.match(/^........$/gim) ); alert( '12345678\r\n一二三四'.match(/^....$/gim) );close();"
复制代码
看来 findstr 问题不少。除了以前cn-dos的willsort总结的,前不久又有人发现了一个:http://bbs.verybat.org/thread-18013-1-2.html
作者: zhouyongjun    时间: 2009-6-23 18:09     标题: 回复 27楼 的帖子

确实牛,但是有疑惑了
.        通配符: 任何字符(findstr的帮助)
我在百度上搜索,字符时有别于字节的:
字符指一个字母或一个字或一个标点或一个符号,不一定几个字节
显然这里的点号是匹配字节了,我用上面的代码测试了,一个汉字要两点才能匹配
有点糊涂了。。。
作者: zqz0012005    时间: 2009-6-23 19:43

findstr /x strings filename,等同于 findstr "^strings$" filename,也等同于 findstr /be "strings" filename
这样的写法有最后行问题(最后行没有回车的情况)。

type filename | findstr /x strings
这样写没有上面的问题。
作者: zqz0012005    时间: 2009-8-14 15:35     标题: 回复 13、14楼 的帖子

(more "%~f0"&echo.)|findstr /o .*
这样会多出额外的空格。

要再加一行,其实多加一个more就行了:
more "%~f0"|more|findstr /o .*




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