Board logo

标题: [文本处理] 批处理中如何用set对=等号进行替换 [打印本页]

作者: amwfjhh    时间: 2014-12-2 22:13     标题: 批处理中如何用set对=等号进行替换

本帖最后由 pcl_test 于 2016-9-8 12:50 编辑

有下方类似样本文本,其中主体信息部分含大量=号,需要将其改变为其它字符以作后续处理:
list.txt
  1. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=A6=88
  2. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E6=AF=9B=E5=93=A5
  3. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=A6=B9=E5=A6=B9
  4. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E4=BA=8C=E4=B8=87
  5. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E6=96=B0=E4=B8=AD=E6=BA=90
  6. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=B0=8F=E7=BF=A0
  7. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=B0=BE=E5=B7=B4
  8. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E7=88=B8=E7=88=B8
  9. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E4=BC=8D=E5=B8=88=E5=82=85
  10. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=B0=8F=E7=BD=97
  11. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E7=89=A9=E7=AE=A1
  12. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85
  13. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=86=92=E8=8F=9C
  14. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=8C=85=E8=BA=AB=E5=B7=A5
  15. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=BF=83=E5=AE=BD=E4=BD=93=E8=83=96
  16. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=B0=8F=E9=B1=BC
  17. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E8=B1=86=E6=B1=A4
  18. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=B0=8F=E8=8D=89
  19. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E4=B9=8C=E9=B8=A6
  20. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E8=B0=A2=E5=A4=84
  21. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E9=91=AB=E9=91=AB
  22. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E8=90=A7=E8=90=A7=E9=BA=BB=E5=B0=86
  23. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=A4=9C=E7=8C=AB
  24. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E8=A5=BF=E6=9C=8D
  25. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E6=B1=AA=E6=B1=AA
  26. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=9B=9B=E4=B8=AA=E5=9C=88
  27. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E7=A7=8B=E7=A7=8B
  28. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E5=B0=8F=E7=BE=A9
  29. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E9=99=88
  30. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=E9=9D=92=E8=9B=99
  31. FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:=31=32=E6=A0=8B
复制代码
拿到题目后一看文本替换自然想到用set, 但具体实施的时候出问题了:SET中文本替换不能对=字符进行处理,试过很多办法,转义=号,转义"号都不起作用,正一筹莫展的时候突然想到论坛里面讨论过对于delims的默认取值及DOS默认分割符的相关讨论,=号正是经典分割符之一,比如echo,for 等均可以识别其为正确分割符,既然如此,就想到以下相对绕弯的方法来达到对set语句中=号替换的作用,如下方代码,就以%号来替换文本中的=号,核心语句恰好也是用的set本家的招式:
  1. @echo off
  2. for /f "tokens=2 delims=:" %%i in (list.txt) do (
  3.   
  4.   for /f "usebackq tokens=*" %%k in (`"(for %%a in (%%i) do @<nul set /p=%%%%a)&echo,"`) do (
  5.     set name=%%k
  6.     call,echo,name = %%name%%
  7.   )  
  8. )
  9. pause
  10. goto :EOF
复制代码

作者: CrLf    时间: 2014-12-3 17:36

理解是对的,但太绕了,4到7行可以简化成:
  1. (set /p"=name="
  2. for %%a in (%%i) do @<nul set /p"=%%%%a"
  3. echo,)<nul
复制代码
----------------------------------------------------
再提供另一种将等号替换为其他字符的方法,无法区分单个等号和连续多个等号,简单来说基本原理是这个:
  1. for /f "delims=" %%a in (^"=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85^") do set name=%%a
  2. call echo name=%%name: =%%
复制代码
而为了兼容其他分隔符和各种特殊字符,还要用到另一个帖子的办法:
[分享]区分引号内外,转义特殊字符
作者: amwfjhh    时间: 2014-12-3 19:41

回复 2# CrLf


    谢谢分享,只是显示的话用你的优化效果非常不错,我里面其实是截取的一部分代码,这是第一个步骤,其实你应该已经猜到了,那其实是一些汉字的uri编码,将其转成可以转码的字符后就可以得到真实文字了。这个例子也是从手机导出名片文件中截取的,它来自于vcf文件。

先学习一下你的分享链接,看看又能收获到什么惊喜……
作者: amwfjhh    时间: 2014-12-3 20:32

回复 2# CrLf


    不知是不是系统差异,我这里加上/f反而还有错误提示,
  1. for /f "delims=" %%a in (^"=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85^") do set name=%%a
  2. call echo name=%%name: =%%
复制代码
去掉反而正常。
  1. @echo off
  2. for %%a in (^"=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85^") do set name=%%a
  3. call echo name=%%name: =%%
  4. pause
复制代码

作者: CrLf    时间: 2014-12-3 21:28

本帖最后由 CrLf 于 2014-12-3 21:30 编辑

回复 4# amwfjhh


那就试试:
  1. for /f "delims=" %%a in (""=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85"") do set "name=%%~a"
  2. call echo name=%%name: =[等号]%%
复制代码
不用 /f 比较害怕字符串含 * 或 ?
作者: amwfjhh    时间: 2014-12-3 22:40

明天换台机子试试,还是有报错。
作者: amwfjhh    时间: 2014-12-4 11:26

回复 5# CrLf

还是有错误提示,出处何在?
作者: amwfjhh    时间: 2014-12-4 11:56

本帖最后由 amwfjhh 于 2014-12-4 15:14 编辑

回复 5# CrLf


    你这个转义IN内等号的方法效率很高,可以批量将=消除而不遍历,有没有基于这个方案的将其替换为%的方法呢,消化完你那篇帖子还要段时间……


PS:自己都看晕了。忘了最简单的办法:
  1. set name=!name: =%%!
复制代码

作者: DAIC    时间: 2014-12-4 13:06

回复 2# CrLf


但是如果字符串里面有空格,替换的时候会发生误伤,求指点啊大神。
  1. @echo off
  2. for /f "delims=" %%i in (^"bbs=bat home=net^") do (
  3.     set str=%%i
  4. )
  5. call set str=%%str: =.%%
  6. echo,%str%
  7. pause
复制代码

作者: amwfjhh    时间: 2014-12-4 13:32

回复 9# DAIC


    这倒可以利用先将空格转换的预处理方式来避免。
  1. @echo off
  2. set "src=bbs=bat home=net"
  3. set "src=%src: =@%"
  4. echo src : %src%
  5. for /f "delims=" %%i in ('echo %src%') do (
  6.     set "str=%%i"
  7. )
  8. echo,after for : %str%
  9. call,set "str=%%str: =.%%"
  10. call,set "str=%%str:@= %%"
  11. echo,dst : %str%
  12. pause
复制代码

作者: DAIC    时间: 2014-12-4 13:37

Win7用户表示鸭梨不大
  1. @echo off
  2. powershell -c "(gc a.txt) -replace '=', '%%'" > b.txt
复制代码

作者: DAIC    时间: 2014-12-4 13:42

回复 10# amwfjhh


    这种方法始终是有局限性,在实际文件的处理中我们不知道会有哪些字符会出现。
作者: amwfjhh    时间: 2014-12-4 13:52

是。我也就遇题解题,要整出通用性的东西来那是大牛们才能干的事。
作者: amwfjhh    时间: 2014-12-4 14:49

本帖最后由 amwfjhh 于 2014-12-4 15:50 编辑

For循环,in后面的条件括号很有意思啊。不知道它具体是怎么工作的。
不开/f开关只认文件与字符两种办理,非文件即字符,即使输入'echo hello'这种语句也被识别为字符串,并且还是断行输出(识别空格为分割符,这里'显然被识别为普通字符)。
开/f开关后会识别三种,字符,命令与文件。回车 兄构建的这个代码
  1. for /f "delims=" %%i in (^"=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85^") do set "str=%%a"
复制代码
或许可以胡乱猜一下,出错的提示为打开文件错误,显然先试着解析的是文件(或许之前先排除过命令,因未找到'而转向下一个处理),并且每次运行提示的文件打开错误内容还不一样,此处可能发生了内存泄漏,文件名指向了一块无意义内存区,然后因找不到而转到下一处理;而后是进行字符串解析(或者命令解析,命令解析会出现不是内部或外部命令的提示,所以这里在第一个字节进行判定的时候即已退出解析而跳至下一阶段),但是如果被作为字符串解析的话,这里已经对"进行了转义,所以str的值应该为带引号的字符串,并且应该完整显示内容,但此处最终被解析的结果来看,引号不见了,等号也被转成空格了(分割符处理),最终的结果类似于echo,=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85。
那此处的(^"=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85^")有可能被最终解析成了另一种形式:流

PS:"被转义,它本身失去了转义效能,因此后面的=被识别为分割符而作统一转换,这是=消失的原因,但"为什么消失就想不通了,按说被转义后它应为普通字符而被显示出来,就像不加/f那样,
  1. for %%a in (^"=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85^") do echo %%a
复制代码
看来/f开关对于字符串的首尾字符是进行宁可错杀,不可放过的政策。
作者: CrLf    时间: 2014-12-5 22:27

回复 14# amwfjhh


我觉得你想复杂了...个人理解,cmd 只是在预处理中把 for~do 之间未转义的分隔符转换成空格,等号就是在预处理中变成空格的
然后当执行到 for 命令的时候,再去检查 in~do 之间的字符串首尾字符,此时已经没有转义的概念了
把这几句保存到 bat 中,回显就是初步的预处理结果
  1. echo on
  2. for /f "delims=" %%a in ('echo =E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85') do echo %%a
  3. for /f "delims=" %%a in ('"echo =E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85"') do echo %%a
  4. pause
复制代码

作者: amwfjhh    时间: 2014-12-6 02:18

回复 15# CrLf


    你举这个例子也从侧面印证了/f时对括号里面的判断,首字节为'时识别为命令,即使里面是一个“看起来是标准字符串”的字符串,带引号字符串与不带引号字符串具有同等效力,只要包含正确命令,都会被执行,区别只是第二句命令被双引号包起来,所以对其中的特殊符号进行了转义,=不再作为分割符。但是echo后的第一字节,[,;= ]等组合还是会被识别成切割符(这是构成命令的要素),不管在双引号内与否,因为这句的最外层是',里面有符合命令特征的,就先按语法解析了。

把几句放到一起看或许更能说明问题,出错在语法解析这一步上:预处理给出了一个可以显示的结果(兼具了命令与字符串二者的特征),但在语法解析时出了问题,既给出了可见回显,又提示文件错误……
  1. prompt $
  2. echo on
  3. for /f "delims=" %%a in ('echo;=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85') do echo,%%a
  4. for /f "delims=" %%a in ('"echo+=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85"') do echo,%%a
  5. for /f "delims=" %%a in ("=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85") do echo,%%a
  6. for /f "delims=" %%a in (^"=E5=AE=89=E8=A1=A3=E6=9F=9C=E9=97=A8=E5=B8=88=E5=82=85^") do echo,%%a
  7. pause
复制代码

作者: amwfjhh    时间: 2014-12-6 02:26

擦喇!灵异事件。
第三个FOR存在时,第四个FOR不报错;第三个FOR用REM注释起来时,第四个FOR就会报找不到文件错误。
彻底凌乱了……
作者: pcl_test    时间: 2016-9-8 13:10

  1. mshta http://bathome.net/s/hta "type('list.txt').replace(/[^:\r\n]+(?=([\r\n]|$))/g, function($0){return decodeURIComponent($0.replace(/=/g,'%%'))})"
  2. pause
复制代码





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