15

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

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

str=45:abc

我想进入45一个变量和abc另一个变量。可以在批处理文件中吗?

模式就像 somenumber:somestring

4

6 回答 6

18

您可以用不同的方式拆分 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 在他的解决方案中使用了带有管道的换行符。
这似乎有点过于复杂。
由于解决方案使用了这样一个事实,即解析器在未转义的换行符之后删除了该行的其余部分(当在特殊字符之前或在特殊字符阶段发现时)。

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

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

!"
set lead=%lead%
echo "!lead!"
于 2013-01-31T08:52:05.837 回答
4

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

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

让我知道。:)

于 2013-01-31T07:52:44.913 回答
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 线程处理。请参阅为什么在管道代码块中延迟扩展失败?对于一个相关问题,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”,无法识别为内部或外部命令、可运行程序或批处理文件。但它似乎只是迷失在醚。

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


不带 FOR 的安全版本

我原来的解决方案不适用于像this & that:cats & 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 正则表达式的怪癖,$它只匹配以 . 结尾的行<cr>。第一行没有,第二行有。该/v选项反转结果。

于 2013-06-13T22:41:28.457 回答
3

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

@echo off
setlocal

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

您可以在此处阅读此方法的完整详细信息。

于 2015-06-07T00:08:22.433 回答
0

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

    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
于 2015-07-06T20:47:02.980 回答
0

鉴于人们在这里发布了各种拆分变量的方法,我不妨发布我自己的方法,允许从一个变量中拆分出多个拆分,用相同的符号表示,这在 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”。

于 2015-07-27T10:35:57.020 回答