【问题标题】:How to split string without for loop in batch file如何在批处理文件中拆分字符串而不使用for循环
【发布时间】:2013-01-15 06:07:04
【问题描述】:

我想将一个字符串分成两部分,不使用任何 for 循环。

例如,我在变量中有字符串:

str=45:abc

我想在一个变量中获得45,在另一个变量中获得abc。批处理文件可以吗?

模式就像 somenumber:somestring

【问题讨论】:

    标签: batch-file dos


    【解决方案1】:

    你可以用不同的方式分割str。

    for 循环,你不想使用它。

    * 的尾随部分很容易(匹配任何内容,直到 ...)
    set "var2=%str:*:=%"

    可以用一个讨厌的技巧来完成前导部分
    set "var1=%str::="^&REM #%

    脱字符号需要插入符号,
    所以有效地冒号将被替换为"&REM # 因此,在您的情况下,您在替换后得到了线路
    set "var1=4567"&REM #abcde
    这分为两个命令

    set "var1=4567"
    REM #abcde` 
    

    完整的代码在这里:

    set "str=4567:abcde"
    echo %str%
    set "var1=%str::="^&REM #%
    set "var2=%str:*:=%"
    echo var1=%var1% var2=%var2%
    

    编辑 2:更稳定的前导部分

    感谢 Dave 提出使用换行符的想法。
    REM 技术对于带有引号和特殊字符的内容不是很稳定。
    但是通过换行技巧,存在一个更稳定的版本,当 split 参数长于单个字符时也可以使用。

    @echo off
    setlocal enableDelayedExpansion
    set ^"str=456789#$#abc"
    for /F "delims=" %%a in (^"!str:#$#^=^
    
    !^") do (
      set "lead=%%a"
      goto :break
    )
    :break
    echo !lead!
    

    解决方案 3:适应 dbenhams 答案

    Dbenham 在他的解决方案中使用了带有管道的换行符。
    这似乎有点过于复杂。
    由于该解决方案使用了这样一个事实,即解析器在未转义的换行符之后删除了该行的其余部分(当在special character phase 之前或中找到它时)。

    首先,冒号字符被替换为换行符,并带有延迟扩展替换。
    这是允许的,换行符现在是变量的一部分。
    然后set lead=%lead% 行去掉尾部。
    最好不要在这里使用扩展语法,因为如果引号是字符串的一部分,set "lead=%lead%" 会中断。

    setlocal enableDelayedExpansion
    set "str=45:abc"
    set ^"lead=!str::=^
    
    !"
    set lead=%lead%
    echo "!lead!"
    

    【讨论】:

    • ^&REM # ...你能解释一下吗?
    • +1 这是很棒的 jeb,比我想出的版本好得多(看到你的后我没有费心发布:))这也适用于 ^&REM - 没有哈希。
    • @BaliC 哈希用于一些讨厌的内容,例如/?
    • 关于编辑 2 - 我认为重点是避免使用 FOR ;-)
    • @dbenham 我知道 :-) 但关键是,这似乎是唯一安全的方法。但是我在没有管道的情况下附加了您的解决方案的简化版本
    【解决方案2】:

    你可以试试这个。如果它固定,冒号左侧的数字将始终为 2,而右侧的数字将始终为 3。假设您的 str 具有该值,则以下代码应该可以工作。

    set "str=45:abc"
    echo %str%
    set var1=%str:~0,2%
    set var2=%str:~3,3%
    echo %var1% %var2%
    

    随时通知我。 :)

    【讨论】:

    • 那么它可能是什么模式?
    • patter 就像 somenumber:somestring ?
    • @user1511510 格式的东西在这里很重要,应该添加到问题中
    • for循环遇到了什么问题?
    【解决方案3】:

    避免使用 FOR 循环似乎毫无意义,但它确实使问题变得有趣。

    正如 jeb 所指出的,使用!str:*:=! 可以轻松获取结尾部分。

    棘手的部分是主要部分。这是jeb的解决方案的替代方案。

    您可以使用以下语法在变量中插入换行符来代替:

    setlocal enableDelayedExpansion
    set "str=45:abc"
    echo !str::=^
    
    !
    

    --输出--

    45
    abc
    

    最后一个! 上方的空行很关键。

    我不知道为什么,但是当上面的输出通过管道传输到命令时,只保留了第一行。因此,可以将输出通过管道传输到与任何行匹配的 FINDSTR,并将结果定向到文件,然后可以使用 SET /P 将其读入变量。

    在使用 SET /P 之前必须删除第二行,因为 SET /P 不能将 <LF> 识别为行终止符 - 它只能识别 <CR><LF>

    这是一个完整的解决方案:

    @echo off
    setlocal enableDelayedExpansion
    set "str=45:abc"
    echo(!str::=^
    
    !|findstr "^" >test.tmp
    <test.tmp set /p "var1="
    del test.tmp
    set "var2=!str:*:=!"
    echo var1=!var1!  var2=!var2!
    

    更新

    我相信我已经大致弄清楚为什么第二行从输出中被剥离了:)

    这与 Windows cmd.exe 处理管道的方式有关,每一端都由一个新的 CMD.EXE 线程处理。请参阅 Why does delayed expansion fail when inside a piped block of code? 了解相关问题,jeb 给出了很好的回答。

    只看管道命令的左侧,我相信它(在内存中)被解析成一个看起来像这样的语句

    C:\Windows\system32\cmd.exe /S /D /c" echo {delayedExpansionExpression}"
    

    我用{delayedExpansionExpression}表示尚未发生的多行查找替换扩展。

    接下来,我认为变量表达式实际上被扩展并且通过搜索和替换将行分成两部分:

    C:\Windows\system32\cmd.exe /S /D /c" echo 43
    abc"
    

    只有这样才能执行命令,并且按照正常的 cmd.exe 规则,命令在换行处结束。带引号的命令字符串缺少结束引号,但解析器并不关心这一点。

    我仍然感到困惑的部分是abc" 发生了什么?我原以为会尝试执行它,导致错误消息像 'abc"' is not Recognized as an internal or external command, operable program or batch file。 但它似乎只是迷失在了以太中。

    注意 - jeb 的第三条评论解释了原因:)


    没有 FOR 的安全版本

    我的原始解决方案不适用于this &amp; that:cats &amp; dogs 之类的字符串。这是一个没有 FOR 的变体,它几乎适用于任何字符串,除了字符串长度限制和尾随控制字符将从前导部分剥离。

    @echo off
    setlocal enableDelayedExpansion
    set "str=this & that:cats & dogs"
    set ^"str2=!str::=^
    
    !^"
    cmd /v:on /c echo ^^!str2^^!|findstr /v "$" >test.tmp
    <test.tmp set /p "var1="
    del test.tmp
    set "var2=!str:*:=!"
    echo var1=!var1!  var2=!var2!
    

    我将扩展延迟到新的 CMD 线程,并且我使用了一个 FINDSTR 正则表达式,$ 只匹配以 &lt;cr&gt; 结尾的行。第一行没有,第二行有。 /v 选项反转结果。

    【讨论】:

    • +1:在这里使用换行符是个好主意,但我想你的分析是错误的。 {delayedExpansionExpression} 已经在 cmd /S/D/c 启动时发生`,因为在新的 cmd 上下文中,延迟扩展被禁用(有规则或错误,延迟扩展是在批处理上下文中完成的,而它只有一行不带括号)。我用%%cmdcmdline%% 对其进行了测试。第二部分的剥离是通过以下规则完成的
    • @jeb - 我想你误解了我的解释。我知道延迟扩展发生在父批次中,而不是新的 cmd 线程中。如果采取措施将扩展推迟到新线程中,则保留这两行。但是,我假设解析器在延迟扩展之前准备 cmd /S/D/c 语句,然后扩展语句,然后在新线程中执行。我也知道cmd /S/D/c... 将在第一个换行符处停止,因此只有 43 被传送到 FINDSTR。但是为什么尝试执行abc" 没有错误呢? abc"去哪儿了?
    • 好的,我误解了你的解释 :-) abc" 被未转义的换行符hard从行中删除。与echo 123%LF%abc 中的相同。其余部分在百分比扩展之后,但在特殊字符阶段开始之前由解析器删除
    • @jeb - 啊,很简单。谢谢:-)
    【解决方案4】:

    是的,我知道这是一个非常古老的话题,但我刚刚发现它,我无法抗拒发布我的解决方案的诱惑:

    @echo off
    setlocal
    
    set "str=45:abc"
    set "var1=%str::=" & set "var2=%"
    echo var1="%var1%"  var2="%var2%"
    

    您可以阅读此方法的完整详细信息here

    【讨论】:

      【解决方案5】:

      这是一个没有讨厌技巧的解决方案

          REM accepts userID@host
          setlocal enableDelayedExpansion
          set "str=%1"
          set "host=%str:*@=%"
          for /F "tokens=1 delims=@" %%F IN ("%str%") do set "user=%%F"
          echo user@host = %user%@%host%
          endlocal
      

      【讨论】:

        【解决方案6】:

        鉴于人们在这里发布了各种拆分变量的方法,我不妨发布我自己的方法,不仅允许一个而且几个拆分出来一个变量,用相同的符号表示,这在 REM 方法中是不可能的(我用了一段时间,谢谢@jeb)。

        使用下面的方法,将第二行定义的字符串分成三部分:

        setlocal EnableDelayedExpansion
        set fulline=one/two/three or/more
        set fulline=%fulline%//
        REM above line prevents unexpected results when input string has less than two /
        
        set line2=%fulline:*/=%
        set line3=%line2:*/=%
        
        set line1=!fulline:/%line2%=!
        set line2=!line2:/%line3%=!
        
        setlocal DisableDelayedExpansion
        
        echo."%line1%"
        echo."%line2%"
        echo."%line3%"
        

        输出:

        "one"
        "two"
        "three or/more//"
        

        我建议使用字符串的最后一个如此创建的分区作为剩余“安全”拆分字符的“bin”。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-11-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-02-27
          • 1970-01-01
          • 1970-01-01
          • 2021-05-20
          相关资源
          最近更新 更多