Batch file 替换字符串中需要转义感叹号,但搜索字符串中不需要转义感叹号(启用延迟扩展的子字符串替换)?

Batch file 替换字符串中需要转义感叹号,但搜索字符串中不需要转义感叹号(启用延迟扩展的子字符串替换)?,batch-file,replace,cmd,escaping,delayedvariableexpansion,Batch File,Replace,Cmd,Escaping,Delayedvariableexpansion,假设要在启用语法时使用感叹号替换某些子字符串,它们必须使用立即(正常)扩展,因为解析器无法区分s表示扩展和文本 但是,为什么必须在替换字符串中转义感叹号?当搜索字符串中的感叹号被转义时,为什么没有必要,甚至没有破坏性呢 以下脚本将替换s,然后按相反顺序输入,因此我希望结果等于初始字符串(当然,初始字符串本身不能包含任何反勾号): 这个结果肯定不是我想要的,最后一个字符串不同: 只要你接电话……: set "DELEXP=%DELEXP:`=!%" ..并更换由^此处,因此转义替换字符串中的感叹

假设要在启用语法时使用感叹号替换某些子字符串,它们必须使用立即(正常)扩展,因为解析器无法区分
s表示扩展和文本

但是,为什么必须在替换字符串中转义感叹号?当搜索字符串中的感叹号被转义时,为什么没有必要,甚至没有破坏性呢

以下脚本将替换
`
在字符串中输入code>s,然后按相反顺序输入,因此我希望结果等于初始字符串(当然,初始字符串本身不能包含任何反勾号):

这个结果肯定不是我想要的,最后一个字符串不同:

只要你接电话……:

set "DELEXP=%DELEXP:`=!%"
..并更换
^此处,因此转义替换字符串中的感叹号,结果正是我所期望的:

但是,当我尝试其他转义组合时(在replace和search字符串中转义感叹号,或者仅在search字符串中转义感叹号),结果还是前面提到的不需要的结果


我浏览了这篇文章,但我找不到对这种行为的解释,因为我了解到,正常(或即时,百分比)扩展在延迟扩展发生之前就已经完成了,甚至可以识别出任何感叹号。此外,插入符号识别和逃逸似乎发生在之后。此外,字符串周围甚至有引号,通常会对解析器隐藏插入符号。

实际上,对于子字符串替换本身,不需要转义。它只在后面的解析阶段才有必要。这就是为什么:

但是,为什么必须在替换字符串中转义感叹号

问题是,即时(正常,
%
)扩展是在相当早期的阶段完成的,而延迟扩展(
),顾名思义,是作为最后的步骤之一完成的。因此,立即展开的字符串也会经过延迟展开阶段。作为证明,将变量
VAR
设置为
值!X
X
0
,然后执行
echo%VAR%
,这样您将得到
Value0

但回到最初的问题,当使用立即子字符串替换时,替换字符串是扩展值的一部分,因此它也会经过延迟扩展阶段。因此,必须转义文字感叹号,以免被延迟的扩展占用。这意味着替换本身不需要转义,它实际上是在之后完成的,因此包含转义的给定替换字符串按字面意义应用

当搜索字符串中的感叹号被转义时,为什么没有必要,甚至没有破坏性呢

由于插入符号识别和转义是在立即展开后发生的,因此搜索字符串按字面处理。此外,搜索字符串被替换,因此不包括在立即子字符串替换的输出中,因此它不会通过延迟扩展阶段


让我们看一下原始示例(仅摘录):

替换
集“DELEXP=%DELEXP:!=`%”
搜索
。结果值是带有感叹号的
string`

使用
set“DELEXP=%DELEXP:^!=`%”
将搜索
^按字面意思,因此当然不会找到任何实例(因此保留了原始字符串中的所有文字
,最后通过延迟扩展进行处理)

替换
设置“DELEXP=%DELEXP:`=!%”
`
替换为
完美,结果字符串是
字符串!具有感叹号马克,但这些都会被随后的延迟扩展所消耗

转义的替换
%DELEXP:`=^!%
`
替换为
^字面意思,因此结果是
string^!与^!感叹号^!马克^;转义随后在延迟扩展阶段进行处理,结果是literal
和返回字符串
字符串!具有感叹号马克最后


据《华盛顿邮报》报道,还有第二个逃逸阶段,即延迟扩张阶段。这一点适用于原始问题中的示例,因为第一次转义(在特殊字符识别阶段)由于周围的引号而被禁用(省略此类转义将导致需要双重转义,如
^!

original   string: string!with!exclamation!marks!
normal  expansion: string!with!exclamation!marks!
delayed expansion: stringexclamation
set "DELEXP=%DELEXP:`=!%"
original   string: string!with!exclamation!marks!
normal  expansion: string!with!exclamation!marks!
delayed expansion: string!with!exclamation!marks!
set "STRING=string!with!exclamation!marks!"
setlocal EnableDelayedExpansion
set "DELEXP=!STRING!"
set "DELEXP=%DELEXP:!=`%"
set "DELEXP=%DELEXP:`=!%"
echo(delayed expansion: !DELEXP!
endlocal