Board logo

标题: [文本处理] 批处理替换文本中的特殊字符等号 [打印本页]

作者: Lumiere    时间: 2009-7-28 09:31     标题: 批处理替换文本中的特殊字符等号

前一阵看到论坛上有个列兵求一个替换文本特定字符的代码,要把文本a.txt中的所有“鸡=7”替换为“鸡=七”,但是其它地方出现的7不能替换为七。链接如下:
http://bbs.bathome.net/viewthread.php?tid=5305&highlight=%CC%E6%BB%BB
刚开始一看没想多,觉得应该很容易,用set命令的替换字符就可以完美解决,可真到了实现阶段,总报错,原来,set命令无法将=替换为其它字符。难怪少有人跟帖。我又想,是不是应为set替换命令因为=是其组成部分,如set var=%str:x=y%,因为里面存在等号,难道是要将=转义么?于是我又尝试用转义符^,%,/,\,=等等转义,可是都无济于事。想来想去,很不甘心。总觉得这样简单的功能强大的批处理不可能做不到。于是沉下心来研究了半天,终于皇天不负有心人。
本来讨厌这么麻烦,但是出于让他人更好理解代码的缘由,不得不交代一下来龙去脉。好了,言归正传,假设目标文本为a.txt,里面内容如下:
  1. aa aaa鸡=7aaaad鸡=7777"替换成"鸡=七sfsf777鸡=777sadf777ss daf7sadfs七七sdaf
  2. 该题要求是将文 本中所有的“鸡=7”替换成“鸡=七”,但是文本中出现的所 有其他的7不能替换成七。
复制代码
解决方案为:
  1. @echo off&setlocal enabledelayedexpansion
  2. call :replace
  3. for /f "delims=" %%a in (b.txt) do (
  4.       set var=%%a
  5.       set var=!var:鸡%char%7=鸡%char%七!&echo !var:%char%==!>>c.txt
  6. )
  7. pause&goto :eof 2>nul
  8. :replace
  9. set /p char=请输入一个文本中不包含的字符:
  10. find /i "%char%" a.txt>nul&&goto replace
  11. for /f "tokens=1* delims==" %%a in (a.txt) do (
  12.     set temp=%%a%char%%%b
  13.     call :loop
  14. )
  15. goto :eof 2>nul
  16. :loop
  17. for /f "tokens=1* delims==" %%m in ("!temp!") do (
  18.         set temp=%%m%char%%%n
  19.         if not "%%n"=="" (goto loop) else echo !temp:~0,-1!>>b.txt
  20. )
复制代码
此处要注意的是,set虽然无法直接将等号=替换为别的字符,但是却可以将别的字符替换为等号=。
好啦,第一次发原创,希望从中收获到的人鼓励一下小菜我,继续努力。。。。。呵呵。。。。。。
PS:突然想到一个问题,就是输入的时候不要输入批处理的某些特殊运算符,如^,!之类的,否则会出错,如果一定要输的话,那先将他们转义,比如^,&,&&,|等,但是!因为是变量组成部分,扩展以后会将命令语句的语法打乱,所以不能用,实在找不到文本中未出现的字符的话,也可以字符串,不过前提一定要尽可能是奇怪的长的组合,因为文本中比如有sdsd这样的字符串,而且此字串正好在=的前面,但是没有dsdd这样的字串,如果输入dsdd的话,虽然文本中没有,可以通过第一轮的findstr,但是两个字串连在一起的时候就变成了s dsdd sdd这样后来将原本的=号重新替换回来的时候将在第一个dsdd部分替换,而不是后来的sdsd dsdd,这样结果就变了,这样的情况需要在替换字符串以后再用findstr过滤一次。在此就不添加!还有替换字符串后重新过滤的代码了,因为比较好实现,自己琢磨吧。
作者: Batcher    时间: 2009-7-28 10:30

能否把那个求助帖的链接更新到顶楼?
作者: keen    时间: 2009-7-28 11:30     标题: 回复 1楼 的帖子

find /i "%char%" a.txt>nul&&goto again


应该是goto replace吧
作者: Lumiere    时间: 2009-7-28 12:20     标题: 回复 2楼 的帖子

batcher兄,已照办……
作者: Lumiere    时间: 2009-7-28 12:27     标题: 回复 3楼 的帖子

多谢巡查兄提醒,已修改。之前因为是针对替换等号写的代码,后来看结合他的提问要求重新写了一个调用代码,在其中调用这段替换字符代码,原先用的是again,后来改为replace,结果那个goto忘记修改了。不过很奇怪,我不改运行效果一模一样,呵呵……
作者: keen    时间: 2009-7-28 12:42     标题: 回复 5楼 的帖子

在你用goto again的时候。我输入=号,批处理立马退出。
作者: Lumiere    时间: 2009-7-28 13:01     标题: 回复 6楼 的帖子

呵呵,特殊的字符结合特定的代码将把语句意思打乱,所以很多字符虽然没有问题我还是照巡查兄说的修改了,毕竟是个错误。多谢指出!后面又对存在的可能bug指明了。希望仁兄达人们多多批判,这样才能更精进,写出没有瑕疵的代码。
作者: zqz0012005    时间: 2009-8-18 13:46

其实,如果大家还记得的话,for %%a in ( set ) do command这个最根本的for命令如果set集合石字符串的话,默认分隔符本身就有等号=,所以此替换问题其实很简单,只不过大家都绕弯路,舍近求远了。没事的时候不一定所有时间都要钻研更难更高级的代码,多温故而知新吧……就此打住。

你说的大家早就考虑过。
其实事情远没有你想的那么简单。
且不说特殊字符,对于for %%i in (!tail!) do set head=!head!#%%i,如果!tail!包含连续的等号呢?
而且空格、逗号、分号、等号都可以作为分隔符。
你的代码把所有分隔符都进行了替换。
还要其他一些特殊情况,比如包含在引号中的分隔符,你的方法将无法替换。

[ 本帖最后由 zqz0012005 于 2009-8-18 14:01 编辑 ]
作者: Lumiere    时间: 2009-8-18 14:04     标题: 回复 8楼 的帖子

呵呵,对啊,for基本格式不能指定分隔符,又想当然了。回去删除,多谢~
作者: ZJHJ    时间: 2009-8-18 22:49

为什么搞的这样复杂呢?不就是aa aaa鸡=7aaaad鸡=7777 替换成
aa aaa鸡=七aaaad鸡=七777 吗?
可以将7a替换成七a ,将7777替换成七777,这样处理还特殊吗???

@echo off
cd.>ja.txt
for /f "delims=" %%a in ('findstr /n .* kk1.txt') do (
        set "var=%%a"
        setlocal enabledelayedexpansion
        set var=!var:*:=!
if not "!var!"==""  set var=!var:7a=七a!
if not "!var!"==""  set var=!var:7777=七777!
        echo.!var!>>ja.txt
        endlocal
)

[ 本帖最后由 ZJHJ 于 2009-8-18 23:00 编辑 ]
作者: zqz0012005    时间: 2009-8-18 22:54

你怎么知道7后面是a或者777?
且你那样不是把“鸭=7a”也换掉了?超量完成任务有时是不行的。。
作者: ZJHJ    时间: 2009-8-18 23:16

aa aaa鸡=7aaaad鸡=7777"替换成"鸡=七sfsf777鸡=777sadf777ss daf7sadfs七七sdaf
该题要求是将文 本中所有的“鸡=7”替换成“鸡=七”,但是文本中出现的所 有其他的7不能替换成七。


应该是照题论事。解决问题要找出个性。不能超出题意,画蛇添足。

[ 本帖最后由 ZJHJ 于 2009-8-18 23:19 编辑 ]
作者: zqz0012005    时间: 2009-8-18 23:21

http://www.bathome.net/viewthread.php?tid=5305
注意,根本不知道这个文本中有哪些字符。
此帖中楼主只是随便给了一个例子。

解决问题当然要针对具体题目,但能正确完成任务才是目标。




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