[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[文本处理] 批处理中call子程序时的诡异情形:莫名丢失部分字符

本帖最后由 namejm 于 2011-4-14 13:49 编辑

  在用批处理抓取百度mp3的过程中,我碰到了一件十分诡异的事情,困扰了我好几天。由于完整代码行数较多,我几乎在每条语句后都echo了变量之后再pause,反复对比观察单步执行结果,苦苦跟踪了好几天,终于找到了问题的所在,从而发现了批处理call子程序时的一个bug。

  现象描述:

  我的目的是从每一个xml文件中取出第一对url,它们的位置分别在第一对<encode>和</encode>与<decode>和</decode>之间,例如,在“005_荷塘月色_凤凰传奇.xml”这个文件中,我要获取的字符串是“http://zhangmenshiting.baidu.com/data/music/536029/VndrWW16XHpoV3hpWndoXWpqWHlrW3B7VmprWXpuXHBqV3VmY6Ona3CqlqOZm3Sal2hpaZpsbZ2XaGlpZpxvbWZlZm1rmWxulZeUlmicaDg$”和“%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3?xcode=bf665e66ef6651f8553396c56deab3f1”,当我用正确的代码去执行的时候,是能够丝毫不差地得到这一对字符串的;当我用错误的代码去执行的时候,获取的结果竟然是“http://zhangmenshiting.baidu.com/data/music/536029/VndrWW16XHpoV3hpWndoXWpqWHlrW3B7VmprWXpuXHBqV3VmY6Ona3CqlqOZm3Sal2hpaZpsbZ2XaGlpZpxvbWZlZm1rmWxulZeUlmicaDg$”和“8DE5989C889//www.tianjinwe.com/tianjin/tjyl/201010/iGJlZGZmaGhjYmRpZ2lva2prbGVmaTc$.mp3”,与正确的执行结果相比,它在获取第二串字符串的时候,不仅把百分号对及其之间的字符都置换为空,更让人惊讶的是,它居然会把.mp3?xcode及它之后的第一个http:之间(含自身)的字符串都“吃”掉了,和后一个<encode>、</encode>这个标记对之间的字符串组合成了一个新的字符串。

  问题所在:

  经过艰苦的跟踪,发现在call子程序的时候,当第一次call子程序执行到set "str=%~1" 这一步的时候,所有的百分号对及其之间的字符串都被当做未赋值的变量引用而被置为空值了,而call子程序做<decode>字符串的替换的时候,当子程序执行到 set "str=%~1" 这一步时,竟然已经把这个xml文件中的第一个</decode>标记给“吃”掉了,而此时,替换字符串 <decode> 的动作尚未发生,for语句截取第一个</decode>之前的字符串的语句尚未执行!

  解决办法:

  把call子程序模块取消,改为在for内部处理,结果很成功。

  存在的问题:

  但这样做又引发了另外一个问题:如果我把所有的<……>和</……>这样的标记对中的字符串取出来,而这样的标记有多少个还是未知数,这种情况下,又该如何处理?如果换成call子程序的话,将可以用if+goto语句轻松实现,但call子程序在接收变量的时候,却容易丢失字符串:不仅会导致百分号对及其之间的字符串丢失,还有可能把其他一些不特定的字符串也丢掉。丢失百分号对及其之间的字符串,其原因很明了:百分号对一般会被识别为变量引用,当变量未被赋值的时候,引用这些变量,其值将为空。但丢失不特定字符串的具体原因,是我一直百思不得其解的,只能大致把这种现象和cmd的预处理机制联系起来。

以下是本次对比所用到的代码:

错误的代码:
  1. @echo off
  2. title 处理结果出错
  3. setlocal enabledelayedexpansion
  4. for %%i in (*.xml) do (
  5.     for /f "delims=" %%j in (%%i) do (
  6.         call :GetUrl "%%j" encode
  7.         call :GetUrl "%%j" decode
  8.         echo %%i
  9.         echo "!Url_encode!"
  10.         echo "!Url_decode!"
  11.         echo.
  12.     )
  13. )
  14. pause
  15. exit
  16. :GetUrl
  17. set "str=%~1"
  18. set "str=!str:*<%2>=!"
  19. for /f "delims=<" %%i in ("%str%") do set "Url_%2=%%i"
  20. goto :eof
复制代码
正确的代码:
  1. @echo off
  2. title 处理结果正确
  3. setlocal enabledelayedexpansion
  4. for %%i in (*.xml) do (
  5.     for /f "delims=" %%j in (%%i) do (
  6.         set "str=%%j"
  7.         set "str=!str:*<encode>=!"
  8.         for /f "delims=<" %%k in ("!str!") do set "Url_encode=%%k"
  9.         set "str=!str:*<decode>=!"
  10.         for /f "delims=<" %%k in ("!str!") do set "Url_decode=%%k"
  11.         echo %%i
  12.         echo "!Url_encode!"
  13.         echo "!Url_decode!"
  14.         echo.
  15.     )
  16. )
  17. pause
复制代码

另外,小小抱怨一下,新版本的论坛程序在编辑帖子的时候真不够友好,竟然找不到排图的按钮。


附件: 您需要登录才可以下载或查看附件。没有帐号?注册
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

各位的发言都很精彩
除了有深入的分析
并且还提供了比较完美的解决方案
真是一语惊醒梦中人啊
不过看来大家的重点都集中在call的时候对百分号对的处理上
尚未见有人对那些不特定字符被“吃”掉的解释
而我发这个帖子的重点正在这里
一直没有找到合理的解释
希望能有人解答我心中疑惑
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

TOP

1# namejm


编辑帖子时“排图的按钮”是什么?
Batcher 发表于 2011-4-17 12:11

当我想把那些图片居中、左对齐或右对齐的时候,竟然找不到按钮来进行这些操作,记得在DZ6下是可以的。
尺有所短寸有所长,学好批处理没商量;
考虑问题复杂化,解决问题简洁化。

心在天山,身老沧州。

TOP

返回列表