批量字符串索引和延迟扩展

batch string indexing and delayed expansion

我已将有问题的代码剥离到有问题的行。为什么第一个回声有效,第二个回声无效?

setlocal enabledelayedexpansion
set /a r=19
set blocks=MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM

for /L %%a in (-%r%,1,%r%) do (
   set /a w2=r
   :: This works
   set line=!blocks:~0,%r%!
   echo( !line!

   ::This does'nt work
   set line=!blocks:~0,!w2!!   
   echo( !line!
)  
exit /b 

已编辑: 我一直在尝试,这一行有效:

call set line=%%blocks:~0,!w2!%%

现在的问题是:有人可以向我解释为什么我必须使用 call 吗?

您应该直接使用带有百分比扩展的 r 变量,只要该值在循环内不发生变化即可。

set line=!blocks:~0,%r%!

或者对其他变量使用辅助循环。

 for /F "tokens=*" %%H in ("!w2!") do (
      set line=!blocks:~0,%%H!
   )

使用!delayed expansion扩展变量的可能方法!在 this post:

中描述了使用其他变量作为子串位置或长度,这些变量可能在代码块内发生变化

要在索引在 FOR/IF 内发生变化时获取子字符串的值,请将子字符串用双百分号括起来,并在命令前加上 call。例如:

call set line=%%blocks:~0,!w2!%%

此方法很好地利用了 call 命令允许重新扩展包含在双百分号中的变量这一事实,如 this question:[=16 的第二个答案中所述=]

BatchLineParser:

1) 阶段:扩展 %var%...

6)阶段:如果命令是CALL,则再次从阶段1开始。

另一种实现上述过程的方法是使用一个额外的FOR命令,通过一个等效的可替换参数来改变索引的延迟扩展,然后对子串使用延迟扩展。这个方法比之前的 CALL 运行得更快:

for %%w in (!w2!) do set line=!blocks:~0,%%w!