Board logo

标题: [文本处理] [已解决]如何根据一个文本列出的字符串替换关系式对另一个文本相应的字符串进行替换 [打印本页]

作者: 沸羊羊    时间: 2016-8-22 09:10     标题: [已解决]如何根据一个文本列出的字符串替换关系式对另一个文本相应的字符串进行替换

本帖最后由 沸羊羊 于 2016-8-31 08:14 编辑

各位,我现在遇到个问题,想请教您一下:
我有两个txt文件,分别为a.txt,b.txt,a.txt里边内容格式为
111111,1
111111,2
111,1
而b.txt里面格式如:
aaa,s,aa,111111,ads,asd
aa,a,ad,111,sd,dd
现在我就是想读取a.txt的每一行数据,比如第一行,在b.txt中对应查找有没有111111,有的话,就将111111替换为1,需要注意的是,在b.txt中只有一行111111,但是a.txt中有两行111111,所以需要在b.txt中添加一行数据,并将111111替换为2,请问这个bat怎么写?
作者: 沸羊羊    时间: 2016-8-22 09:42

或者我想问下,能否先复制查找到的字符串所在行,再进行替换操作?
作者: 沸羊羊    时间: 2016-8-22 10:37     标题: 批处理 替换字符串

我现在有两个文件,分别是a.txt,b.txt
我想循环读取a.txt的每一行数据,然后在b.txt中,行一一对应的替换字符串(b.txt文件中,已经经过排序,所以是必定与a.txt中的数据一一对应的)
请问,这个bat脚本怎么写?文件格式见附件
作者: GNU    时间: 2016-8-22 15:49

回复 3# 沸羊羊
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. (for /f "tokens=1-8 delims=," %%a in ('type "b.txt"') do (
  4.     set /p StrLine=
  5.     for /f "tokens=2 delims=," %%x in ("!StrLine!") do (
  6.         set StrCol=%%x
  7.     )
  8.     echo ,%%a,%%b,!StrCol!,%%d,%%e,%%f,%%g,%%h
  9. ))<"a.txt" > "c.txt"
复制代码

作者: 沸羊羊    时间: 2016-8-22 16:37

回复 4# GNU


    大神,您的脚本确实实现了我的需求,不过我是新手,能不能麻烦您给我详细解释下各行的意思呢?万分感谢!
作者: 沸羊羊    时间: 2016-8-23 08:36

  1. @echo off
  2. rem setlocal enabledelayedexpansion
  3. if exist C:\"Program Files"\"aa bb"\test.txt del /q C:\"Program Files"\"aa bb"\test.txt
  4. if exist C:\"Program Files"\"aa bb"\c.txt del /q C:\"Program Files"\"aa bb"\c.txt
  5. set file=C:\Program Files\aa bb\a.txt
  6. set file2=C:\Program Files\aa bb\20160818_Export_c.txt
  7. set "tmpFile=C:\Program Files\aa bb\c.txt"
  8. set "dirFile=C:\Program Files\aa bb\test.txt"
  9. for /f "tokens=1,2 delims=," %%a in ("%file%") do (
  10. for /f "tokens=*" %%i in ('type "%file2%" ^| findstr %%a') do (
  11. echo %%i>>"%tmpFile%"
  12. )
  13. rem call :G_getrows "C:\Users\fan-17\Desktop\a.txt" kk
  14. )
  15. setlocal enabledelayedexpansion
  16. (for /f "tokens=1-8 delims=," %%a in ('type "%tmpFile%"') do (
  17.     set /p StrLine=
  18.     for /f "tokens=2 delims=," %%x in ("!StrLine!") do (
  19.         set StrCol=%%x
  20.     )
  21.     echo ,%%a,%%b,!StrCol!,%%d,%%e,%%f,%%g,%%h
  22. ))<"%file%" > "%dirFile%"
  23. if exist "%tmpFile%" del /q "%tmpFile%"
复制代码
回复 4# GNU


    您好,这是我结合您给的脚本,写的一个批处理,如果文件路径中没有空格,则可以执行,但是如果路径中有空格,就会提示找不到文件,我在网上找资料,说是只要在有空格的路径上加双引号就行,可是我加了之后还是没用,请您指教
作者: GNU    时间: 2016-8-23 09:43

回复 6# 沸羊羊


一个路径加一对双引号就够了。
  1. if exist "C:\Program Files\aa bb\test.txt" del /q "C:\Program Files\aa bb\test.txt"
复制代码

作者: GNU    时间: 2016-8-23 09:44

  1. @echo off
  2. set "file=C:\Program Files\aa bb\a.txt"
  3. set "file2=C:\Program Files\aa bb\20160818_Export_c.txt"
  4. set "tmpFile=C:\Program Files\aa bb\c.txt"
  5. set "dirFile=C:\Program Files\aa bb\test.txt"
  6. if exist "%tmpFile%" del /q "%tmpFile%"
  7. if exist "%dirFile%" del /q "%dirFile%"
  8. for /f "tokens=1,2 delims=," %%a in ("%file%") do (
  9.     for /f "tokens=*" %%i in ('type "%file2%" ^| findstr %%a') do (
  10.         >>"%tmpFile%" echo %%i
  11.     )
  12.     rem call :G_getrows "C:\Users\fan-17\Desktop\a.txt" kk
  13. )
  14. setlocal enabledelayedexpansion
  15. (for /f "tokens=1-8 delims=," %%a in ('type "%tmpFile%"') do (
  16.     set /p StrLine=
  17.     for /f "tokens=2 delims=," %%x in ("!StrLine!") do (
  18.         set StrCol=%%x
  19.     )
  20.     echo ,%%a,%%b,!StrCol!,%%d,%%e,%%f,%%g,%%h
  21. ))<"%file%" > "%dirFile%"
  22. if exist "%tmpFile%" del /q "%tmpFile%"
复制代码
如果这个代码还是报错,你可以把 @echo off 删掉,在CMD窗口执行 test.bat 这样可以看到具体是哪里在报错。
作者: 沸羊羊    时间: 2016-8-23 10:54

本帖最后由 沸羊羊 于 2016-8-23 11:04 编辑

回复 8# GNU


    您好,根据您的脚本,执行后,发现报错,注释掉echo off,查看执行结果,发现 我的临时文件 c.txt 没有生成,这个是怎么回事?

我逐行执行脚本,发现  for /f "tokens=1,2 delims=," %%a in ("%file%") do (
echo %%a

这句话,输出的%%a 是个路径,而不是 文本内容的值,是不是双引号加的不对导致的?
作者: GNU    时间: 2016-8-23 11:30

回复 9# 沸羊羊


那种写法会导致 for 命令认为 "%file%" 是个字符串而不是一个文件
改成这样试试:
for /f "tokens=1,2 delims=," %%a in ('type "%file%"') do (
作者: 沸羊羊    时间: 2016-8-23 12:22

回复 10# GNU


    谢谢,长知识,确实好用
作者: 沸羊羊    时间: 2016-8-24 09:48

本帖最后由 沸羊羊 于 2016-8-24 10:12 编辑

回复 10# GNU
  1. @echo off
  2. rem 号与号的对应文件
  3. set file=C:\Program Files\aa bb\a.txt
  4. rem 文件
  5. set file2=C:\Program Files\aa bb\20160818_Export_c.txt
  6. rem 生成的临时文件,最后会删掉
  7. set tmpFile=C:\Program Files\aa bb\c.txt
  8. rem 生成的新的文件
  9. set dirFile=C:\Program Files\aa bb\test.txt
  10. if exist "%tmpFile%" del /q "%tmpFile%"
  11. if exist "%dirFile%" del /q "%dirFile%"
  12. for /f "tokens=1,2 delims=," %%a in ('type "%file%"') do (
  13.     for /f "tokens=*" %%i in ('type "%file2%" ^| findstr %%a') do (
  14.         >>"%tmpFile%" echo %%i
  15.     )
  16. )
  17. setlocal enabledelayedexpansion
  18. (for /f "tokens=1-8 delims=," %%a in ('type "%tmpFile%"') do (
  19.     set /p StrLine=
  20.     for /f "tokens=2 delims=," %%x in ("!StrLine!") do (
  21.         set StrCol=%%x
  22.     )
  23.     echo ,%%a,%%b,!StrCol!,%%d,%%e,%%f,%%g,%%h
  24. ))<"%file%" > "%dirFile%"
  25. if exist "%tmpFile%" del /q "%tmpFile%"
复制代码
请问,如何在 'type "%file2%" ^| findstr %%a' 时,判断有没有查找到字符串呢?没有的话则跳过,有的话,则输出到临时文件中
还有,能不能一行行复制,而不是根据逗号分隔,再输出1-8列,这样就被限制死了。谢谢!
作者: xxpinqz    时间: 2016-8-24 13:18

回复 12# 沸羊羊

没找到本来就不执行写入tmpfile,一行一行的替换需要考虑有两列及其以上的字段相同时,会替换其它的值。
作者: GNU    时间: 2016-8-24 13:37

回复 12# 沸羊羊


判断有没有查找到字符串呢?没有的话则跳过,有的话,则输出到临时文件中

代码14行到16行就是为了实现这个功能
作者: 沸羊羊    时间: 2016-8-24 14:06

回复 14# GNU


    我试了下,确实可以,只是执行太慢,以为是卡死在那了,还有最后一个问题,能不能做到一行行的替换,而不是使用tokens=1-8,限定了输出列数?
作者: 沸羊羊    时间: 2016-8-24 14:07

回复  沸羊羊

没找到本来就不执行写入tmpfile,一行一行的替换需要考虑有两列及其以上的字段相同时,会 ...
xxpinqz 发表于 2016-8-24 13:18



    您好,如果不需要考虑有两列或以上字段相同的情况,能否做到行替换?谢谢
作者: GNU    时间: 2016-8-24 18:00

回复 15# 沸羊羊
  1. @echo off
  2. setlocal enabledelayedexpansion
  3. (for /f "delims=" %%a in ('type "b.txt"') do (
  4.     set LineB=%%a
  5.     set /p LineA=
  6.     for /f "tokens=1-2 delims=," %%x in ("!LineA!") do (
  7.         set LineNew=!LineB:%%x=%%y!
  8.     )
  9.     echo !LineNew!
  10. ))<"a.txt" > "c.txt"
复制代码

作者: 沸羊羊    时间: 2016-8-25 08:16

回复 17# GNU


    大神您好,暂时我还看不懂您写的脚本都是什么意思,但是行复制是做到了,但是你的脚本会把每行的字符串都替换掉,这样的话,我的“被替换”的字符串相同,“替换值”不同,就只替换了一个

可能表达的不是特清楚
a.txt                                  b.txt                                             临时文件
111111  1                          ,a,b,c,111111,s,f,g                        ,a,b,c,111111,s,f,g
111111   111                                                                        ,a,b,c,111111,s,f,g

由于 a.txt 中,有两个 111111 ,所以我现在生成的临时文件中,已经将b.txt中包含字符串“111111”的行做了复制
现在我就需要 一行将 “111111”替换为“1”,一行替换为“111”

或者我想到一个折中的办法,就是每次只替换查找到的第一个字符串,其余的都不替换,只是我不会写这个脚本,麻烦您了,谢谢!
作者: GNU    时间: 2016-8-25 10:17

回复 18# 沸羊羊


    我是根据3楼文件写的代码,请举例说明代码执行的结果和你希望的结果具体差别在哪里。
作者: 沸羊羊    时间: 2016-8-25 10:38

本帖最后由 沸羊羊 于 2016-8-25 10:39 编辑

回复 19# GNU


    您好:
             代码执行结果是:在b.txt中,先查找到 “111111”,然后替换为“1”,再执行第二行,查找“111111”,此时,由于“111111”已经全部替换为“1”了,所以找不到,这样就是全部替换为“1”了
             我要的效果是: a.txt中,有几行包含“111111”的,就在b.txt中,复制包含“111111”的行,然后,根据a.txt中第二行的值,一一替换
             具体说明,可以看 我在18楼回复您时,临时文件的替换效果
作者: GNU    时间: 2016-8-25 11:54

回复 20# 沸羊羊


很遗憾,那个代码是根据你之前的需求编写的:a.txt和b.txt的行一一对应
你现在新的需求根本不是一一对应,所以这个代码无法正常处理。
作者: GNU    时间: 2016-8-25 11:55

请把最新需求的a.txt和b.txt两个文件以及希望得到的新文件c.txt打包压缩传上来
作者: 沸羊羊    时间: 2016-8-25 12:16

回复 22# GNU

我就是想根据a.txt里面的数据,替换掉b.txt里面的字符串,然后生成test.txt,a.txt中的字符串,在b.txt中没有的话,就跳过
作者: 沸羊羊    时间: 2016-8-29 08:39

回复 22# GNU


    您好,我已经把文件和想要的效果发出,麻烦您给个脚本,急求,拜谢!
作者: happy886rr    时间: 2016-8-29 10:45

回复 24# 沸羊羊
一行就完事,何必搞这么复杂,下载第三方sed
  1. for /f "tokens=1-3 delims=:," %%a in ('findstr /n .* a.txt') do (sed -i "%%as/,%%b,/,%%c,/" b.txt)
复制代码

作者: 沸羊羊    时间: 2016-8-29 10:56

回复 25# happy886rr


    您好,第一:由于公司后台杀毒软件,我还没下载sed.exe,就给我直接删掉了
               第二:由于需要支持win7、win8、win xp,所以,sed 能全面支持吗?
               第三:sed.exe能不能支持静默安装?如果可以,我可以尝试在安装包中加入这个程序安装,然后再调用
作者: happy886rr    时间: 2016-8-29 11:06

本帖最后由 happy886rr 于 2016-8-29 11:17 编辑

回复 26# 沸羊羊
这个根本不用安装,直接用。支持主流系统,你把sed直接跟要替换的文件放一起,然后运行那个批处理就完事。sed有很多版本,你下个免杀版的就行。

如果你们公司杀软很厉害,那就安个虚拟机,在虚拟机里操作替换,然后把资料从虚拟机里取出来。就下载那个virtual PC2007虚拟机才30M,再下载个30M的xp系统,搭建个虚拟机,在里边随便搞。还可以研究病毒。
作者: GNU    时间: 2016-8-29 11:06

回复 26# 沸羊羊


2. 支持
3. 不需要安装。可以放到bat同一个目录,或者放到C:\Windows\System32文件夹,然后就能直接使用了。
作者: 沸羊羊    时间: 2016-8-29 11:40

回复 27# happy886rr


    您好,我把您的脚本,放到bat中,然后下载了sed.exe,并且,我将a.txt、b.txt、sed.exe和bat 脚本都放在一个文件夹下,执行bat,提示我参数使用不对
作者: 沸羊羊    时间: 2016-8-29 11:47

回复 28# GNU


    谢谢!,其实我还是挺愿意,使用bat,而不是借助第三方来解决的,但是如果第三方不需要安装,那也是可以尝试下的
作者: happy886rr    时间: 2016-8-29 11:47

回复 29# 沸羊羊
你用的啥系统啊。还有要单独一个批处理,不要跟别的代码混用在一起。
作者: 沸羊羊    时间: 2016-8-29 12:32

回复 31# happy886rr


    win7 ,我直接将你的脚本复制到一个新的bat中,然后执行
作者: GNU    时间: 2016-8-29 12:43

回复 29# 沸羊羊


C:\Test>sed --version
sed (GNU sed) 4.2.2

看看你下载的哪个版本,老版本的 sed 可能不支持 -i
作者: 沸羊羊    时间: 2016-8-29 14:39

回复 25# happy886rr


    您好,我也没找到sed的教程,能不能帮我解释下,这段脚本的意义?
作者: happy886rr    时间: 2016-8-29 15:49

回复 34# 沸羊羊
  1. for /f "tokens=1-3 delims=:," %%a in ('findstr /n .* a.txt') do (sed -i "%%as/,%%b,/,%%c,/" b.txt)
复制代码
这个代码没问题,我是32位win7系统,我下载你提供的a、b.txt测试了5遍,没有任何问题。得到的b.txt与你要求的test.txt完全一致。

其中'findstr /n .* a.txt'就是给a.txt编上行号,
"tokens=1-3 delims=:,"是用:提取行号和用,号提取a.txt中的数据
sed -i "%%as/,%%b,/,%%c,/" b.txt中的%%as是替换一一对应行的内容,将%%b(也就是你所说的1111111)替换成%%c(也就是你所说的1)
for /f就是文本循环,从a.txt的第一行一直循环到最后一行。

可能是你控制台设置里“当前代码页编码不对”是否为gbk936编码。
作者: 沸羊羊    时间: 2016-8-30 14:23

回复 35# happy886rr


    您好,感谢您的详解,谢谢
作者: 沸羊羊    时间: 2016-8-30 14:51

回复 33# GNU


    您好,请问您有没有详细一点的,批处理教程,我想深入学习批处理,谢谢!
作者: Batcher    时间: 2016-8-30 16:37

回复 34# 沸羊羊


这里有 sed 教程,Linux和Windows绝大部分内容是通用的。
http://bbs.bathome.net/thread-13203-1-1.html
作者: Batcher    时间: 2016-8-30 16:42

回复 37# 沸羊羊


试试这两个教程
http://bbs.bathome.net/thread-14608-1-1.html
http://bbs.bathome.net/thread-31727-1-1.html

微信群会不定期进行在线分享,也会发布到微信公众号,欢迎多多关注
http://bbs.bathome.net/thread-3473-1-1.html
作者: 沸羊羊    时间: 2016-8-30 16:57

回复 39# Batcher


    非常感谢!已申请QQ群,但是微信公众号显示不了?
作者: Batcher    时间: 2016-8-30 18:07

回复 40# 沸羊羊


http://bbs.bathome.net/thread-3473-1-1.html
如果你看不到这个帖子里面的所有图片,请检查一下是否已经登录了,www和bbs两个域名需要分别登录的。




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