Board logo

标题: [文本处理] 新人学习,文本替换 [打印本页]

作者: zydrawer    时间: 2018-2-6 16:12     标题: 新人学习,文本替换

本帖最后由 zydrawer 于 2018-2-6 19:52 编辑

先贴码:
@echo off&setlocal enabledelayedexpansion
for /f "delims=" %%a in (findfile.txt)do (
        set /a num=0
        set h1=%%a
        echo %%a
        for /f "tokens=1,2 delims=        " %%i in (key.txt)do (
                set h2=!h1:%%i=%%j!
                if !h1! neq !h2! (
                                echo !h2! >>d.txt
                        )else (
                        if !num! == 0 (
                        echo !h2! >>d.txt
                        set /a num = num+1
                        ))
                        ))
set num=
pause
目的:查找关键字并将其替换为指定字符串
有两个文本文档.txt      findfile.txt         key.txt
key.txt是关键字文本有两列 之间是与tab键隔开,形式如下
第一列            第二列
11111            aaaaa
222222          bbbbbbbb
pppp              cccccccc
。。。            。。。。
findfile.txt 文件是待查找文件 这个文件的内容中是含有key.txt文件中第一列的关键字
找到第一列的关键字后用第二列的字符串替换掉第一列的关键字
其他不变,然后将结果输出到另一个文件中

问题:
我写的bat处理命令虽将字符串替换成功,但是也将没有替换的行也重复输出了,
花了好久时间也没有找到原因,拜托各位前辈大神了
作者: 523066680    时间: 2018-2-6 19:58

劝退:换其他脚本语言吧。
作者: zydrawer    时间: 2018-2-6 20:36

回复 2# 523066680


    你这打击新人的积极性么
作者: yhcfsr    时间: 2018-2-7 02:37

  1. if !h1! neq !h2! (
  2.                                 echo !h2! >>d.txt
  3.                         )else (
  4.                         if !num! == 0 (
  5.                         echo !h2! >>d.txt
  6.                         set /a num = num+1
  7.                         )
复制代码
根据你这段,如果存在没有被替换的行,必然会输出且只会输出首次没有被替换的行。
作者: /zhqsystem/zhq    时间: 2018-2-7 04:34

本帖最后由 /zhqsystem/zhq 于 2018-2-7 04:38 编辑
  1. for /f "tokens=1,* delims=tab分割符" %%i in ('type key.txt')do (
  2. set "#="
  3. for /f "delims=" %%k in ('type findfile.txt')do if /i "%%i"=="%%k" set "#=y"
  4. if defined # (
  5.   echo,%%jtab分割符%%j
  6. )else (
  7.   echo,%%itab分割符%%j
  8. )
  9. )
复制代码

作者: zydrawer    时间: 2018-2-7 09:57

回复 5# /zhqsystem/zhq


    首先感谢答主热心解答。
关于答主的if /i "%%i"=="%%k" 有些不解,
可能是我描述问题不清楚,之前没有对findfile.txt进行说明
findfile.txt只是包含有key.txt中第一列的关键字,也就是说关键字只是findfile.txt中每一行的子串,关键字位置并不在行首
所以我认为这里不应该用等号吧
作者: zydrawer    时间: 2018-2-7 10:05

回复 4# yhcfsr


    感谢指出不足指出
我运行后的结果是,无论有没有替换,它都会输出原行(未经替换的行),若是存在替换的过程,他会在打印原行之后再次打印替换后的行(这个先后循序,然我感到很迷惑,就像是先执行了else语句后再执行if语句)
而我要求是:若不存在要替换的关键字,则直接打印输出,若存在,则只打印输出替换后的行
作者: zydrawer    时间: 2018-2-7 10:09

再次看到4楼5楼的回复时间,再次感谢
作者: yhcfsr    时间: 2018-2-7 16:12

本帖最后由 yhcfsr 于 2018-2-7 16:21 编辑

从你整个代码来看,执行逻辑是这样的:
先读取源文本某行(假设行号为x),再读取关键字文本(假设总共有n行)。
如果读关键字文本第一行时,x行中没找到需要替换的“11111”关键字,就输出原行;如果找到“11111”,就替换再输出替换后的行。

如果在读取关键字文本第一行进行了替换操作,那你的判定条件“h1 neq h2”恒成立,也就是说从在读取关键字文本第二行开始,如果有替换就输出替换后的x行,如果没有替换,就重复输出上一次被替换后的x行内容。总共输出n次x行。
如果在读取关键字文本第一行没有进行替换操作,输入一次x行的原行后,不会再输出x行的原行。假设读取关键字文本第m行开始进行首次替换操作,判定条件“h1 neq h2”恒成立,之后会输出x行(n-m)次,加上第一行输出的原行,共输出(n-m+1)次x行。
所有对于源文本的任何一行,都有可能输出多次。

我想你的目的应该是源文本中的任何一行,对关键字文本进行检索替换后,只输出一次。要实现这个目的,要在读取完关键字文本所有行进行的替换操作后,再输出该行。
作者: /zhqsystem/zhq    时间: 2018-2-7 19:21

本帖最后由 /zhqsystem/zhq 于 2018-2-7 19:31 编辑

回复 6# zydrawer
这是整行完整对比[多个空格都会对比失败],如果有对比成功则激活输出替换,如果没有则原始输出
以下是每句的解释
rem解释只限本行,在看不懂我也没办法,对于新学有难度

for /f "tokens=1,* delims=tab分割符" %%i in ('type key.txt')do (rem:加载主文本
set "#="&&rem:标记清空
for /f "delims=" %%k in ('type findfile.txt')do if /i "%%i"=="%%k" set "#=y"&rem:加载对比数据,当主文本指定=任意行内的数据则标记变量
if defined # (rem:存在标记则有数据相等
   echo,%%jtab分割符%%j
)else (rem:不存在标记则没有数据相等
   echo,%%itab分割符%%j
)
)
作者: slore    时间: 2018-2-8 00:01

回复  523066680


    你这打击新人的积极性么
zydrawer 发表于 2018-2-6 20:36



花了好久时间没有解决,说明这个事用批处理不方便,如果自己需要解决问题,而不是学习批处理,完全没有必要死磕批处理。

1.楼主用了2层for循环,每一行替换把key.txt要重新读取一边,效率低。
2.要使用延时变量,搞得代码变量使用要注意,对新手,基础不是很好的话,明明自己思路对的但是代码却不是按自己想的走。
3.如果KEY.TXT里面有某些特殊字符,set h2=!h1:%%i=%%j!的方式替换,导致语法错误出错,不能解决楼主问题。

如果把批处理当解决问题工具的话,有其他东西能简单搞定也愿意使用的话,文本,字符串处理交给别的脚本语言是正确的,系统自带的VBS也行,不过代码多些。

比如楼主的问题,用ruby脚本语言,不使用特殊用法刻意减少代码行数,纯粹按最简单的逻辑处理,使用基本语法,不到10行还简单明白。
  1. text = File.read('findfile.txt') #读取全部内容保存到text变量
  2. kvlist = File.read('key.txt')             #读取key.txt文件内容
  3. kvlist.each_line do |line|               #并按行循环
  4.     line = line.chomp                     #去掉末尾\r\n换行符
  5.     if line.length > 0                      #不是空行的话
  6.         kv = line.split("\t") #Tab      #按Tab分割得到KEY,VALUE数组
  7.         text.gsub!(kv[0], kv[1])       #替换内容
  8.     end
  9. end
  10. File.write('findfile_2.txt', text)
复制代码
问题:
我写的bat处理命令虽将字符串替换成功,但是也将没有替换的行也重复输出了,
花了好久时间也没有找到原因,拜托各位前辈大神了
zydrawer 发表于 2018-2-6 16:12


批处理很简单,一行一行走,查看每行的数据和自己的预期是否一致就能找出问题。
简单的调试方法:

findfile.txt只写简单的2行,key.txt先写2行。
abc def 123 456 777
abc 888 456 123

33 ccc
456 xxx

然后把echo off改成echo on,自己在cmd下运行看每行执行的结果,尤其是在输出文件前,可以自己echo单独看看。
echo xxx > b.txt => echo xxx b.txt

另外,大体一看有2处不是很明白,
if !h1! neq !h2!
为什么要判断替换后是否相同?
abc def 123 456 777找不到33没有替换为ccc那么它还是abc def 123 456 777,直接输出就行。
abc def 123 456 777再找到456替换为abc def 123 xxx 777,直接输出,为什么要判断找到与否?

if !num! == 0 (
为什么要记录替换次数?一行只替换一次么?比如abc 33 456的话,只把33替换为ccc,456就不再替换为xxx了是么?描述的需求里面没有体现。
作者: yhcfsr    时间: 2018-2-8 19:46

  1. @echo off
  2. set "SrcFile=F:\Test\findfile.txt"
  3. set "KeyFile=F:\Test\key.txt"
  4. for /f "delims=" %%a in ('findstr /n .* "%SrcFile%"') do (
  5.         set "var=%%a"
  6.         setlocal enabledelayedexpansion
  7.         set var=!var:*:=!
  8. if "!var!" neq "" for /f "usebackq tokens=1,2 delims= " %%i in ("%KeyFile%") do set "var=!var:%%i=%%j!"
  9. (echo.!var!)>>"%SrcFile%.log"
  10.         endlocal
  11. )
  12. pause&exit
复制代码





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