Board logo

标题: [文本处理] [已解决]批处理启动变量延迟后尖号二次预处理仍会转义 [打印本页]

作者: Lumiere    时间: 2009-3-26 15:24     标题: [已解决]批处理启动变量延迟后尖号二次预处理仍会转义

二、启动了变量延迟之后预处理又是如何进行呢?

    我的看法是这样的:如果语句中存在英文叹号“!”则会被预
处理两次,其它情况仍然是预处理一次。由于脱字字符比较特殊,
,因此在此借助该符号写几个例子说明一下。
(一)
  1.       @echo off
  2.         echo !^^^^^>
  3.         setlocal enabledelayedexpansion
  4.         echo !^^^^^>
  5.         pause
  6.       
复制代码
两个echo语句的结果不同。下面做一下分析:
对于第一个echo语句,变量延迟没有开启,进行预处理的时候该句
就被预处理为“echo !^^>”,这也就是输出的结果。由此可见预
处理只进行了一次。
对于第二个echo语句,此时变量延迟开启,由于有“!”存在,首
先进行一次预处理得到“echo !^^>”,再进行一次得到“echo ^>
”,结果也是如此。
之所以没有输出叹号,是因为开启了变量延迟,叹号就变为了特殊
符号。
……
下面是非常批处理里英雄写的几个关于此论题的帖子,地址附上:
http://bbs.verybat.org/viewthread.php?tid=8593&extra=page%3D1    脱字符
http://bbs.verybat.org/viewthread.php?tid=10141&pid=171977&page=2&extra=#pid171977   还是预处理


省略号之前的是楼主的原文,从第二个连接里复制到的。我有个疑惑,说出来大家别指责我这个菜鸟,在此先深深像英雄大侠表示尊敬,很感谢他为所有的菜鸟呕心沥血写了那么多好文章。
疑惑的地方就是这句话:“对于第二个echo语句,此时变量延迟开启,由于有“!”存在,首
先进行一次预处理得到“echo !^^>”,再进行一次得到“echo ^>
”,结果也是如此。”
我记得他写了好几个帖子,都是关于批处理脱字符还有预处理以及变量延迟扩展的,很有幸小弟都一一拜读了。我还记得脱字符那篇是这样讲的,当脱字符^是偶数的时候,比如是2k,这些脱字符统统预处理为k个普通意义上的字符^,而后面的特殊符号保留其特殊意义,在上面那段话里,第一次预处理以后是echo !^^>,没问题,这里只有两个^,是偶数,那么找道理应该进行第二次预处理以后就解释成echo !^>,单此时>仍然保留了它的特殊意义,为什么显示会是echo !^>呢?照道理会像输入echo >一样报错才对。另外我又尝试将刚开始的echo !^^^^^>变成echo !^^^^^^^>,多了两个^^,其他代码不变,运行以后结果也是echo !^>,我觉得这样才是符合英雄大哥所讲的关于脱字符那片文章的。
不知道是不是我脑子看多了晕了,有什么地方没看到,如果是,请大家毫不留情的予以指正。如果不是的话,还请大家再讨论讨论。多谢!

[ 本帖最后由 Lumiere 于 2009-8-10 00:04 编辑 ]
作者: Lumiere    时间: 2009-3-26 15:59

哎呀,弄不明白很不爽啊,茶不思饭不想的……自己顶一下,希望论坛达人早日看到!
作者: Lumiere    时间: 2009-3-26 16:43     标题: 自己顶

有没有人看见这个帖子啊,在线等很长时间了,麻烦哪位高人给讲解一下,拜托!
作者: Batcher    时间: 2009-3-26 16:57

在开启变量延迟的情况下,如果想在包含感叹号的字符串中输出n个尖号,至少要使用4*n个尖号,至多要使用4*n+2个尖号。

因为要进行两次预处理,第一次预处理后,4*n个尖号变为2*n个,第二次预处理后,2*n个尖号变为n个,最终输出。

如果你使用了4*n+2个尖号,第一次预处理后,尖号变为2*n+1个,第二次预处理时,这个“落单”的尖号会被抛弃掉,最终还是输出n个。
作者: Lumiere    时间: 2009-3-26 17:03     标题: 回复 4楼 的帖子

规则我都看过了,了解,可是“落单”的^为啥就那么不值钱就无端端抛弃了呢?如果不启动延迟扩展的话不会出现这样的情况的吧?batcher多谢你回复,能否给我再讲解下?我的帖子不完全是^这个符号,你自己看下代码就知道,后面还跟了一个特殊字符>,不会连这个也被无情抛弃了吧?

[ 本帖最后由 Lumiere 于 2009-3-26 17:07 编辑 ]
作者: Lumiere    时间: 2009-3-26 17:59     标题: 麻烦大家多看看,值得研究的

好郁闷啊,一下午就等到一个回复。希望大家给点耐心认真看完我的帖子,里面关于脱字符,变量延迟,call机制还有>的关系很值得研究一下的。麻烦论坛的达人了。
作者: tireless    时间: 2009-3-26 18:03

因为预处理后 > 已经变成了普通字符,“变量延迟扩展”它的任务就是延迟扩展变量,其他事不管,只不过还顺带处理一下 ^ 符号。

我觉得微软把“变量延迟扩展”设计成仅仅延迟扩展变量比较好,而不要再处理 ^。说不定这是一个 BUG......

另一个例子:
  1. @echo off&setlocal enabledelayedexpansion
  2. set "var=&"
  3. echo !var!
  4. pause
复制代码
再次说明了“变量延迟扩展”仅仅是“单纯”地延迟扩展变量。

[ 本帖最后由 tireless 于 2009-3-26 18:16 编辑 ]
作者: Lumiere    时间: 2009-3-26 18:17     标题: 回复 7楼 的帖子

我看你说的是一个可信的说法。第一次预处理以后就被当作普通字符了。不过我似乎看过其他的代码,好像不管转义了没有,只要进行二次预处理好像还是当作特殊字符的啊,但是我不记得具体在哪里看的了,现在好混乱啊。
作者: zqz0012005    时间: 2009-3-26 18:18

那就一步步来,
echo !^^^^^>
echo !^^>
^>

echo !^^^^^^^>
echo !^^^>
^>

至于前一个代码第一次预处理后的语句echo !^^>为什么不会出错,英雄的帖子有解释,这里不再赘述。

还有什么疑问?
作者: Lumiere    时间: 2009-3-26 18:25     标题: 回复 9楼 的帖子

我觉得7楼的哥们讲得更让人信服。英雄的帖子很好,我就是看他的帖子有些不明白,那段讲的不是很明确,
echo !^^^^^>
echo !^^>
^>
上面的中间那条,是第一次预处理得到的结果,里面有两个^啊,到底第一个^转义第二个^还是第二个^转义最后的>得到的结果呢?从你的回复来看你似乎是说第一个^转义了第二个^,对吧?那么>呢?不转义么?如果转义的话,那么在原始代码中多加俩^的话,第一预处理结果是^^^>,在预处理一次,显示结果还是^>,那就说明最后的>还是被转义了,不是么?

[ 本帖最后由 Lumiere 于 2009-3-26 18:29 编辑 ]
作者: tireless    时间: 2009-3-26 18:31     标题: 回复 10楼 的帖子

从左至右,即前面的 ^ 把后面的 ^ 进行转义,前面的 ^ 就消失了。

如果原代码再加俩 ^:

echo !^^^^^^^>
echo !^^^>
echo ^>

一种颜色一对,加了下划线的把后面的转义,自己消失。

[ 本帖最后由 tireless 于 2009-3-26 18:39 编辑 ]
作者: zqz0012005    时间: 2009-3-26 18:40

回复 7楼 的帖子
其实这还是与预处理有关(英雄已指出:预处理时要判断语句的结构和功能)。
预处理时从echo !var!中没有发现&等功能字符,判定这一句的功能是一条普通的显示命令,变量展开时&被当作普通字符输出。

开启变量延迟后对含有!的语句要再次进行处理,但不再决定语句的结构和功能。
不仅是^,还有for解析的文本含有!时也会再次处理。这个可能算得上是Bug,但没办法,也是特性带来的。

回复 10楼 的帖子
看来还是要赘述一下。英雄帖子里说过,预处理是从左到右依次处理。第一次预处理时由于>被^转义,系统判定这一句命令的功能不是重定向,预处理后的echo !^^>,后面那个>便被当作“普通字符”了,,因此再次处理时不需要转义也不会出错。

[ 本帖最后由 zqz0012005 于 2009-3-27 09:48 编辑 ]
作者: zqz0012005    时间: 2009-3-26 18:42

注意,7楼tireless兄的代码与楼主提到的形式不是同一个类型。
  1. @echo off
  2. echo !^^^^^>
  3. setlocal enabledelayedexpansion
  4. echo !^^^^^>
  5. set "var=^^^^^>"
  6. echo !var!
  7. pause
复制代码
setlocal EnableDelayedExpansion 启用延迟的变量扩展,的确仅仅是“单纯”地延迟扩展变量。但变量总是要展开的,预处理时变量扩展被延迟了,必然还有一次对变量进行展开的处理。这次处理是依据语句中有没有!进行的,而不是根据有没有!对。于是这种依据产生了一个缺陷:对任何含有!的语句都要进行再次处理。
已分析出的结论:语句的结构和功能是在预处理时决定的
对于echo !var!,预处理时从该句中没有发现&、|、>等功能字符,判定这一句的功能是一条普通的显示命令,再次处理时直接将展开后的变量值原样输出。
而echo !^^^^^>,由于后面>被^转义,系统判定这一句的功能也是一条普通的显示命令,而不是重定向。预处理后该句变为echo !^^>。由于该句包含!,于是要被再次处理。注意^^>并不是包含于!对,这次处理并不是对该句进行变量展开,而是对这一条语句进行普通处理。^还是转义符,但根据上面的结论>不再有重定向功能,相当于普通字符。
根据这些原理不难分析下面的代码:
  1. echo off&setlocal enabledelayedexpansion
  2. set "^^^^^>=1"
  3. echo !^^^^^^^^^^^>!
  4. pause
复制代码

[ 本帖最后由 zqz0012005 于 2009-3-27 10:50 编辑 ]
作者: Lumiere    时间: 2009-3-26 20:46     标题: 回复

echo !^^^^^^^> 这种情况不用多说,我理解。但是echo !^^^^^>最后结果是^>实在有点想不通。版主也说“预处理是从左到右依次处理。后面那个>已经是被当作普通字符了”,我在想,第一次预处理以后不是所有剩下来的特殊字符都被当做是普通字符了么?因为都转义了,并不是只有后面那个>被转义了啊。
echo !^^^^^>和echo !^^^^^^^> 不一样,运行结果却一样,他们的差别到底在那里呢?第一次预处理之后,它们两个命令分别变成echo !^^>和echo !^^^>,照理说,预处理以后它们的特殊字符不管是^还是>都被转义了,都是普通字符,为什么第二次预处理第一个命令里的^会再次转义,而>就不转义了呢?而echo !^^^>因为有三个^,中间的^和最后的>都转义,这样的话,不就矛盾了么?同样的字符,同样的预处理过程,按道理第一个命令会提示命令格式错误才对的吧?
作者: myzwd    时间: 2009-3-26 23:46     标题: 回复 1楼 的帖子

  1. setlocal enabledelayedexpansion
  2. echo !^^^^^^^^^^^^^^^x  15个
  3. echo !^^^^^^^^^^x   10个
复制代码
第一次脱去一半,第二次又脱去一半。差的半个舍掉。
echo !^^^^^^^^^^^^^^^x  15个
第一次脱掉一半,还有7.5个^,还留下7.5个,半个舍掉,此时剩下7个,第二次有脱掉一半,留下3.5个,半个舍掉,就等于留下三个,最后看到的也是3个 !^^^x
echo !^^^^^^^^^^x
第一次脱一半 得 !^^^^^x  (5个),第二次有脱一半 留下2.5个 半个舍掉,就留下的是2个
此时看到的是 !^^x
。这种问题 我认为就象脱百论(%)一样,我个人认为没多少实际意义。你编程的时候,会弄这么多“^”吗?把它当数学游戏,我觉得还比较合适。
作者: Lumiere    时间: 2009-3-27 09:24     标题: 回复楼上

多谢楼上的回复,不过你说的只是结果,对于编程的人结果不是最重要的,过程才是最重要的。渔和鱼哪个重要?来龙去脉搞不清楚的话以后还是会出问题的。你这个解释法只是有意忽略本质看现象,不是透过现象看本质。
作者: Lumiere    时间: 2009-3-27 09:32

这样说吧,其实大家都没有认真去看帖子也没有认真的当回事来想。也怪我自己对问题陈述不清楚吧。
首先在开启变量延迟的情况下,代码如果这样:echo !^^^^^>,第一次预处理后得到echo !^^>,这一步好理解。接下来呢,就出现不同的解释:1.第一个^被忽视,抛弃,就是说上面第一步得到的结果中的第二个与>经过第一预处理后都被当成普通字符显示,第一个^被丢掉;2.照非常批处理里面一个人对英雄帖子的回复说法来看,预处理是从左至右逐个处理字符的,那么势必第一个^转义第二个^得到一个^,后面的>咋办,它落单了,是抛弃还是直接当作普通字符显示? 3.基于第二种情况和最终的显示结果,>没有被抛弃,那就说明它经过第一次预处理之后就被当作了普通字符,可是这样的话又矛盾了,它前面的俩^不都是经过第一次预处理以后得到的么?那也应该被当作普通字符一块显示出来才对啊?除非^相比>或者其他特殊字符更特殊,有更蹊跷而独特、专有的法则。
第一次预处理后得到echo !^^>,再预处理执行以后就显示^>,但是如果我们就直接输入命令echo !^^>回车的话就提示命令格式不对。it doesn't make sense.
还请各位大侠多多释疑,小弟在此感激涕零。

[ 本帖最后由 Lumiere 于 2009-3-27 10:05 编辑 ]
作者: tireless    时间: 2009-3-27 10:52     标题: 回复 17楼 的帖子

你就当做 ^ 永远是转义字符,再加上7楼的解释,这样就可以解释所有。然后把这个问题放一放,或许以后会明白。




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