代码之家  ›  专栏  ›  技术社区  ›  goulashsoup

批处理-延迟扩展不适用于周围的if子句

  •  2
  • goulashsoup  · 技术社区  · 6 年前

    在下面的脚本中,我用一个字符串、该字符串的子字符串的最大长度和第三个不存在的变量调用一个子例程,以返回子字符串。

    脚本应该检查具有最大子字符串长度的字符串后面的下一个字符是否是空格,如果是,则将字符串剪切该空格(将空格删除为),并返回子字符串,并通过剪切子字符串部分更改传递的字符串。例子:

    字符串:“你好,世界布拉”
    子串长度:5

    CALL :get_substring string substringLength substring

    =>字符串:“world bla”(无空格),子字符串长度:5(无更改),子字符串:“hello”

    这在没有if子句的情况下可以正常工作,但在使用if子句时却不行,即使使用延迟扩展也是如此。

    以下是不带if语句的工作代码:

    @ECHO OFF
    SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
        SET string=Hello World wasserschutzpolizei
        SET /A substringLength=5
        CALL :get_substring string substringLength substring
        ECHO !string!
        ECHO !substring!
        EXIT /B 0
    ENDLOCAL
    
    :get_substring
        SETLOCAL ENABLEDELAYEDEXPANSION
    
        SET "string=!%~1!"
        SET "substringLength=!%2!"
        SET nextChar=!string:~%substringLength%,1!
    
        REM IF "!nextChar!"==" " (
            SET substring=!string:~0,%substringLength%!
            ECHO !substring!
            SET /A cutSpaceCount=!substringLength!+1
            SET string=!string:~%cutSpaceCount%!
    
            ECHO !string!
    
            ENDLOCAL & SET %1=%string% & SET %3=%substring% & EXIT /B 0
        REM ) ELSE (
        REM     Some other case    
        REM )
    
    EXIT /B 0
    

    当我在if语句中评论时,这不起作用:

    IF "!nextChar!"==" " (
        SET substring=!string:~0,%substringLength%!
        ECHO !substring!
        SET /A cutSpaceCount=!substringLength!+1
        SET string=!string:~%cutSpaceCount%!
    
        ECHO !string!
    
        ENDLOCAL & SET %1=%string% & SET %3=%substring% & EXIT /B 0
    ) ELSE (
        REM Some other case    
    )
    
    1. 为什么脚本不能与if语句一起使用?
    2. 如何修复?

    请注意,我的程序还应该包括一个我删掉的else语句,因为问题是相同的。

    3 回复  |  直到 6 年前
        1
  •  4
  •   Aacini    6 年前

    问题在于这一行:

    SET string=!string:~%cutSpaceCount%!
    

    当此行放置在 IF 命令,然后 cutSpaceCount 已更改 里面 的代码块(括号) 如果 ,因此必须通过 !cutSpaceCount! 延迟膨胀, 通过A %cutSpaceCount% 标准扩展。

    您应该使用类似于“双延迟扩展”的方法,即类似于此构造:

    SET string=!string:~!cutSpaceCount!!
    

    for 命令获取 第一 延迟扩展,然后使用 for参数 要完成第二次延迟扩展:

    for /F %%c in ("!cutSpaceCount!") do SET "string=!string:~%%c!"
    

    当子例程中的最终值返回到调用程序时,也会发生类似的问题。这是最终工作代码:

    @ECHO OFF
    SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
        SET string=Hello World wasserschutzpolizei
        SET /A substringLength=5
        CALL :get_substring string substringLength substring
        ECHO !string!
        ECHO !substring!
        EXIT /B 0
    ENDLOCAL
    
    :get_substring
        SETLOCAL ENABLEDELAYEDEXPANSION
    
        SET "string=!%~1!"
        SET "substringLength=!%2!"
        SET "nextChar=!string:~%substringLength%,1!"
    
        IF "!nextChar!"==" " (
            SET "substring=!string:~0,%substringLength%!"
            ECHO !substring!
            SET /A cutSpaceCount=!substringLength!+1
    
            for /F %%c in ("!cutSpaceCount!") do SET "string=!string:~%%c!"
    
            ECHO !string!
            for /F "delims=" %%s in ("!string!") do for /F "delims=" %%b in ("!substring!") do (
                ENDLOCAL & SET "%1=%%s" & SET "%3=%%b" & EXIT /B 0
            )
    
        ) ELSE (
            ECHO Some other case    
        )
    

    ps-不需要在 SET /A 命令。而不是:

    SET /A cutSpaceCount=!substringLength!+1
    

    您可以简单地使用:

    SET /A cutSpaceCount=substringLength+1
    
        2
  •  3
  •   Magoo    6 年前

    您似乎对调用延迟扩展时发生的操作序列非常困惑。

    首先,价值 var 替换为 %var% .

    然后!var!使用结果进行评估。

    这个 范围 这一系列的操作是 符合逻辑的 行,可以是一行 身体的 线路或任何数量的物理线路与终端相连 ^ 或者更常见地使用带括号的行序列。

    在你的主线上,

    CALL :get_substring string substringLength substring
    ECHO !string!
    ECHO !substring!
    ENDLOCAL & SET %1=%string% & SET %3=%substring% & EXIT /B 0
    

    因为这些陈述是 在同一个 符合逻辑的 行,他们会 个别地 经过评估,所以 !var! = %var % .

    在子程序(非if版本)中,

        SET substring=!string:~0,%substringLength%!
        ECHO !substring!
        SET /A cutSpaceCount=!substringLength!+1
        SET string=!string:~%cutSpaceCount%!
    
        ECHO !string!
    

    同样是个别陈述。第一个 set 将首先替代 substringlength ,然后执行 SET substring=!string:~0,5! 作为第二次手术。

    每个 echo ES是一个独立的声明,并且 ! 可以(最好应该)替换为 % .

    这个 set /a 声明-好吧, SET/A 允许 现在的 要未修饰的变量的值,因此 SET /A cutSpaceCount=substringLength+1 SET /A cutSpaceCount=%substringLength%+1 可以在这里使用,但没有逻辑效果。

    ENDLOCAL & SET %1=%string% & SET %3=%substring% & EXIT /B 0 将根据前一个代码序列建立的值进行评估。

    然而 当你添加 if 代码用括号括起来,因此成为一个逻辑语句,并且行为不同。

    这个 回声 然后是 要求 ! 因为你想显示 被改进的 中的值 代码块 . 自从 cutSpaceCount 不是在代码块开始处设置的, SET string=!string:~%cutSpaceCount%! 将被评估为 SET string=!string:~!

    然后 endlocal&set%1=%string%&set%3=%substring%&exit/b 0 将适当地替换变量的值 当他们站在 IF 遇到了

    因此,替换程序可能是

    :get_substring
    SETLOCAL ENABLEDELAYEDEXPANSION
    
    SET "string=!%~1!"
    SET "substringLength=!%2!"
    SET "substring=!string:~0,%substringLength%!"
    SET "string=!string:~%substringLength%!"
    IF "%string:~0,1%"==" " SET "string=%string:~1%"
    ENDLOCAL & SET "%1=%string%" & SET "%3=%substring%"
    EXIT /B 0
    
        3
  •  1
  •   aschipfl    6 年前

    正如其他人已经解释过的,问题在于:

    SET string=!string:~%cutSpaceCount%!
    

    因为你使用了即时扩展( % )对于变量 cutSpaceCount 在同一逻辑行/代码块中更改。

    可能的解决方案是 call 这样地:

        call set "string=%%string:~!cutSpaceCount!%%"
    

    呼叫 引入另一个变量展开阶段,因此顺序如下:

    1. 立即扩展阶段,其中 %% 变成 % :

      call set "string=%string:~!cutSpaceCount!%"
      
    2. 然后发生延迟扩展(假设一个样本值为 5 ):

      call set "string=%string:~5%"
      
    3. 另一个直接扩展阶段由 呼叫 最终得到 %string:~5% .