Board logo

标题: [文本处理] 【挑战】将文本中指定位置的tab替换为普通字符 [打印本页]

作者: batman    时间: 2009-6-23 17:21     标题: 【挑战】将文本中指定位置的tab替换为普通字符

本人原意是想用批处理将a.txt中各列的数值进行累加计算(计算本身是很容易
的),但问题是a.txt中各列中有的不是数值而是空(实际上是tab),必须要先将这些指
定位置的tab替换为0字符,才能正确计算出结果。如果是在excel表中操作这会是很容易
的,但就是想用批来完成,想破了头终于还是有了些头绪。同时,本人觉得这个问题还
是有拿出来讨论的价值,所以就发了出来,也请大家各显神通,来完成这个批处理对文
本的特殊替换吧。(因论坛无法处理tab,所以上传附件a.txt如下)
[attach]1600[/attach]

[ 本帖最后由 batman 于 2009-6-23 17:24 编辑 ]
作者: batman    时间: 2009-6-23 17:40

提示下:a.txt中各列间也是以tab来分隔的。
作者: 随风    时间: 2009-6-23 17:49

确定每行最多的是4例吗?连姓名一起是5例。
作者: batman    时间: 2009-6-23 17:52

总列数可以从第一行中提取,如只想就原文本来解答,那就定为5列吧。
作者: 随风    时间: 2009-6-23 18:18

就原文本来解答
  1. @echo off&setlocal enabledelayedexpansion
  2. set "tab=#"&rem 把左边的#号替换为 tab 键
  3. for /f "delims=" %%a in (ss.txt) do (
  4.    set "str=%%a"
  5.    set "str=!str:%tab%%tab%%tab%%tab%=%tab%0%tab%0%tab%0%tab%!"
  6.    set "str=!str:%tab%%tab%%tab%=%tab%0%tab%0%tab%!"
  7.    set "str=!str:%tab%%tab%=%tab%0%tab%!"
  8.    if "!str:~-1!"=="%tab%" set "str=!str:~0,-1!%tab%0"
  9.    echo !str!
  10. )
  11. pause
复制代码
从第一行中提取总列数
  1. @echo off&setlocal enabledelayedexpansion
  2. set "tab= #"&rem 把左边的#号替换为 tab 键
  3. set /p var=<ss.txt
  4. for %%a in (!var!) do (
  5.    set /a n+=1
  6.    for /l %%i in (1 1 !N!) do set t=!t!%tab%&set tt=!tt!%tab%0
  7.    set t!n!=!t!&set t!n!!n!=!tt:~0,-1!
  8.    set t=&set "tt="
  9. )
  10. set /a n-=1
  11. for /f "delims=" %%a in (ss.txt) do (
  12.    set "str=%%a"
  13.    for /l %%i in (!n! -1 2) do (
  14.       for /f "tokens=1,2 delims=/" %%j in ("!t%%i!/!t%%i%%i!") do (
  15.          set "str=!str:%%j=%%k!"
  16.     ))
  17.    if "!str:~-1!"=="%tab%" set "str=!str:~0,-1!%tab%0"
  18.    echo !str!
  19. )
  20. pause
复制代码

作者: netbenton    时间: 2009-6-23 19:22

我也来试试
  1. @echo off&setlocal enabledelayedexpansion
  2. set Tab=        &rem 这个空白换为Tab键
  3. for /f "delims=" %%a in (a.txt) do (
  4.         set var=%%a
  5.         set str=
  6.         for %%b in ("!var:%Tab%=" "!") do (
  7.                 set #%%~b=%%~b
  8.                 set #=0
  9.                 set str=!str!%Tab%!#%%~b!
  10.         )
  11.         echo !str:~1!
  12. )
  13. pause
复制代码

[ 本帖最后由 netbenton 于 2009-6-23 19:24 编辑 ]
作者: pusofalse    时间: 2009-6-23 19:55

  1. @echo off & SetLocal enabledelayedexpansion
  2. :: tab 键
  3. set "tab= "
  4. For /f "skip=1 delims=" %%a in (a.txt) do (
  5. set "sString=%%a" & set "sVar="
  6. set "sString=!sString:%tab%=%tab%#!"
  7. set /a n = 0 & call :recur !sString:~1!
  8. )
  9. set _ & Pause & exit /b
  10. :recur
  11. set /a n += 1
  12. For /f "tokens=1* delims=%tab%" %%a in ("%*") do (
  13. set "sVar=%%a" & set "sVar=!sVar:#=!"
  14. If "!sVar!" equ "" ( set "sVar=0" )
  15. set /a _!n! += sVar
  16. If "%%b" neq "" ( call :recur %%b )
  17. )
复制代码

作者: netbenton    时间: 2009-6-23 20:17

再来个更简单的。
  1. @echo off&setlocal enabledelayedexpansion
  2. set Tab= &rem 这个空白换为Tab键
  3. for /f "delims=" %%a in (a.txt) do (
  4. set var=%%a
  5. set var=!var:%Tab%=%Tab%#!%Tab%
  6. set var=!var:#%Tab%=0%Tab%!
  7. set var=!var:#=!
  8. echo !var:~,-1!
  9. )
  10. pause
复制代码
改成这样就不畏惧任何字符了:
  1. @echo off
  2. set Tab= &rem 这个空白换为Tab键
  3. for /f "delims=" %%a in (a.txt) do (
  4. set var=%%a
  5. setlocal enabledelayedexpansion
  6. set var=!var:%Tab%=%Tab%#!%Tab%
  7. set var=!var:#%Tab%=0%Tab%!
  8. set var=!var:%Tab%#=%Tab%!
  9. echo !var:~,-1!
  10. endlocal
  11. )
  12. pause
复制代码

[ 本帖最后由 netbenton 于 2009-6-24 07:48 编辑 ]
作者: zqz0012005    时间: 2009-6-23 20:41

也是一个比较经典的问题。

for /f 中两个分隔符之间的空值如何表示?
http://bbs.verybat.org/viewthrea ... romuid=37#pid166173
作者: jackerloo2009    时间: 2009-6-23 21:07     标题: 我要好好学习

哎!man在群里让我做一下,呵呵,寻思半天还是来看答案了

喜欢8楼的思路

又掌握了一种思路技巧
作者: tireless    时间: 2009-6-23 23:05

  1. @echo off&setlocal enabledelayedexpansion
  2. set "tab=        " 引号里的空格换成 Tab
  3. for /f "delims=" %%a in (a.txt) do (
  4.   set var=%%a
  5.   set var="!var:%tab%="%tab%"!"
  6.   set var=!var:""=0!
  7.   echo !var:"=!
  8. )
  9. pause
复制代码
  1. @echo off&setlocal enabledelayedexpansion
  2. for /f "delims=" %%a in (a.txt) do (
  3.   set var=%%a
  4.   set n=0
  5.   for %%a in ("!var:【Tab】=" "!") do set /a n+=1 , _!n!+=%%~a 2>nul
  6. )
  7. set _
  8. pause
复制代码

[ 本帖最后由 tireless 于 2009-6-24 09:12 编辑 ]
作者: netbenton    时间: 2009-6-24 07:37

楼上第一个代码可以减少一行,"号用得错实妙

第二个代码似乎结果不正确吧?
是不是想做成6楼的样子呢?


再来一个:
  1. @echo off
  2. set Tab= &rem 这个空白换为Tab键
  3. for /f "delims=" %%a in (a.txt) do (
  4. set var=%%a%Tab%
  5. setlocal enabledelayedexpansion
  6. set var=!var:%Tab%%tab%=%Tab%0%Tab%!
  7. set var=!var:%Tab%%tab%=%Tab%0%Tab%!
  8. echo !var:~,-1!
  9. endlocal
  10. )
  11. pause
复制代码

[ 本帖最后由 netbenton 于 2009-6-24 07:50 编辑 ]
作者: tireless    时间: 2009-6-24 08:48     标题: 回复 12楼 的帖子

正确吧?跟 7楼 的结果一样。

[ 本帖最后由 tireless 于 2009-6-24 09:13 编辑 ]
作者: batman    时间: 2009-6-24 09:47

呵呵,各位都给出了精彩的解答,可能本人在楼顶没有描述清楚,其实最后应该是
要计算出各列的和的,本人代码如下:
  1. @echo off&setlocal enabledelayedexpansion
  2. set "tab=#" rem请将#替换为tab键
  3. for /f "delims=" %%a in (a.txt) do (
  4.      echo %%a&set /a m=0
  5.      set "str=%%a"&set "str=!str:%tab%=%tab%0!"
  6.      for %%b in (!str!) do (
  7.           set /a m+=1
  8.           set "var=%%b"&set "var=!var:~1!"
  9.           if not defined var set /a var=0
  10.           set /a _!m!+=!var!
  11.      )
  12.      
  13. )
  14. set "_1=合计"
  15. for /l %%a in (1,1,%m%) do (
  16.      set /p=!_%%a!<nul
  17.      if %%a neq %m% set /p=%tab%<nul
  18. )
  19. pause>nul
复制代码

[ 本帖最后由 batman 于 2009-6-24 11:44 编辑 ]
作者: tireless    时间: 2009-6-24 10:26

  1. @echo off&setlocal enabledelayedexpansion
  2. set "Tab=#"   把 # 换成 Tab 键
  3. for /f "skip=1 delims=" %%a in (a.txt) do (
  4.   set var=%%a
  5.   set n=0
  6.   for %%a in ("!var:%tab%=" "!") do set /a n+=1 , _!n!+=%%~a 2>nul
  7. )
  8. more a.txt
  9. for /l %%a in (1 1 %n%) do set end=!end!%tab%!_%%a!
  10. echo 合计%end%
  11. pause>nul
复制代码

作者: batman    时间: 2009-6-24 10:45

set /a居然能够兼容汉字符及其他非数值字符,才发现原来可以这样:
set /a a=汉字,b=z,c=#,d=_
只是都默认值为0。
作者: tireless    时间: 2009-6-24 11:11     标题: 回复 16楼 的帖子

set /? 中有说:
在表达式中的任何非数字字符串键作为环境变量
名称,这些环境变量名称的值已在使用前转换成数字。如果指定
了一个环境变量名称,但未在当前环境中定义,那么值将被定为
零。


这个很有意思:
  1. @echo off
  2. set v=,1
  3. set /a v=v
  4. echo %v%
  5. pause  变量 v 的值变为 0
  6. set v=1,
  7. set /a v=v
  8. echo %v%
  9. pause  变量 v 的值变为 1
复制代码

作者: Batcher    时间: 2009-6-24 11:22     标题: 回复 14楼 的帖子

合计的结果有问题吧?
C:\Test>type test.bat
@echo off&setlocal enabledelayedexpansion
set "tab=   " rem请将#替换为tab键
for /f "delims=" %%a in (a.txt) do (
     echo %%a&set /a m=0
     set "str=%%a"&set "str=!str:%tab%=%tab%0!"
     for %%b in (!str!) do (
          set /a m+=1
          set "var=%%b"&set "var=!var:~1!"
          if not defined var set /a var=0
          set /a _!m!+=!var!
     )

)
set "_1=合计"
for /l %%a in (1,1,%m%) do (
     set /p=!_%%a!<nul
     if %%a neq %m% set /p= <nul
)
pause>nul

C:\Test>test.bat
姓名    第一项作业      第二项作业      第三项作业      第四项作业
甲      30      63      83      86
乙      27      93      98      22
丙      94      45      77
丁      14              94      78
戊              81      25      57
己      62      58      75
庚      70      49      10      47
辛      98                      2
壬      95      10      81      12
癸      64      29      45      57
合计 35 46 44 24

作者: batman    时间: 2009-6-24 11:45

回楼上,没有问题啊,你再运行下看
作者: zqz0012005    时间: 2009-6-24 12:04     标题: 回复 17楼 的帖子

  1. @echo off
  2. set m=1,2
  3. set /a n=%m%
  4. echo %n%
  5. set /a n=m
  6. echo %n%
  7. pause
复制代码
有点意思。
set /a n=%m%,即set /a n=1,2,其中,是逗号运算符。逗号表达式的值取最后一个子表达式的值。
  1. set m=2+2
  2. set /a n=m
  3. set "2+2=1" 设置变量2+2
  4. set /a n=m
  5. pause
复制代码

作者: tireless    时间: 2009-6-24 12:29     标题: 回复 20楼 的帖子

17 楼不是因为“逗号是运算符”。换成这样也可以:
  1. @echo off
  2. set v=bathome1
  3. set /a v=v
  4. echo %v%
  5. pause  变量 v 的值变为 0
  6. set v=1bathome
  7. set /a v=v
  8. echo %v%
  9. pause  变量 v 的值变为 1
  10. set v=1bathome
  11. set /a v=%v%
  12. echo %v%
  13. pause  而这样会出错
复制代码

[ 本帖最后由 tireless 于 2009-6-24 12:33 编辑 ]
作者: zqz0012005    时间: 2009-6-24 12:43

我是说set /a n=1,2是逗号运算符。

而你的例子再一次说明了变量名以数字开头的弊端。
作者: zqz0012005    时间: 2009-6-24 13:42

在表达式中的任何非数字字符串键作为环境变量
看来这个也是需要深入理解的。
把 set /a expression 简化成下面的形式,以便于分析:
set /a n=表达式
注意这里的表达式是预处理后的,比如set /a n=%var%,是先把变量var展开再处理。
而set /a n=var,是不需要预处理的(或者说该语句预处理后是它本身)。至于对字符串var的处理,是set自己的功能,而不是预处理的功劳。

1、如果表达式中出现了非数字、非运算符的字符串,则set将这些字符串作为变量名,遵循下面两点:
(1)如果这些字符串是跟在数字后面,则变量名识别会出现问题:set不把它作为变量名,而是试图解析为某种进制中的数字常数。
如,set /a n=12bat,“bat”这些字符不是10进制的常数0-9。
甚至,set /a n=0xbad,这种十六进制形式其实也可以这样理解:首先当然不把xbad作为变量名,而是作为八进制的数字常数,事实上八进制的数字常数只能是0-7,但碰巧第一个字母是x,set转而把它识别为十六进制。

(2)如果字符串后面有数字,这些数字将不再是“数字”,而是变量名的一部分。如果后面是运算符,仍然是运算符。
如,set /a n=bat12,不是%bat%12,而是%bat12%。
而set /a n=bat+12,就是%bat%+12。

2、如果变量未定义,或变量指向的值是非数字,直接替换为0。
如,set var=bathome&set /a m=var, n=undefined,m、n的值都是0。

3、如果变量指向的值包含数字,则从左边开始,如果是数字字符(0-9),则被保留,直到遇到非数字字符,非数字及以后的内容直接被舍弃。
如,set var=12+3&set /a n=var,n的值是12。

[ 本帖最后由 zqz0012005 于 2009-6-24 13:49 编辑 ]




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