本帖最后由 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的预处理机制联系起来。
以下是本次对比所用到的代码:
错误的代码:- @echo off
- title 处理结果出错
- setlocal enabledelayedexpansion
-
- for %%i in (*.xml) do (
- for /f "delims=" %%j in (%%i) do (
- call :GetUrl "%%j" encode
- call :GetUrl "%%j" decode
- echo %%i
- echo "!Url_encode!"
- echo "!Url_decode!"
- echo.
- )
- )
- pause
- exit
-
- :GetUrl
- set "str=%~1"
- set "str=!str:*<%2>=!"
- for /f "delims=<" %%i in ("%str%") do set "Url_%2=%%i"
- goto :eof
复制代码 正确的代码:- @echo off
- title 处理结果正确
- setlocal enabledelayedexpansion
-
- for %%i in (*.xml) do (
- for /f "delims=" %%j in (%%i) do (
- set "str=%%j"
- set "str=!str:*<encode>=!"
- for /f "delims=<" %%k in ("!str!") do set "Url_encode=%%k"
- set "str=!str:*<decode>=!"
- for /f "delims=<" %%k in ("!str!") do set "Url_decode=%%k"
- echo %%i
- echo "!Url_encode!"
- echo "!Url_decode!"
- echo.
- )
- )
- pause
复制代码
另外,小小抱怨一下,新版本的论坛程序在编辑帖子的时候真不够友好,竟然找不到排图的按钮。
|