Как разбить строку без цикла в пакетном файле

Я хочу разбить строку на две части, не используя цикл for.

Например, у меня есть строка в переменной:

str=45:abc

Я хочу получить 45 в переменной и abc в другой переменной. Возможно ли это в пакетном файле?

шаблон похож на somenumber: somestring

Ответы

Ответ 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: Более стабильная ведущая часть

Спасибо Дэйву за идею использования перевода строки.
Технология 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!"

Ответ 2

Вы можете попробовать это. Если зафиксировано, что числа слева от двоеточия будут всегда 2, а справа будет 3. Затем следующий код должен работать, если ваша str имеет значение.

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

Держи меня в курсе.:)

Ответ 3

Кажется бессмысленным избегать использования цикла FOR, но это делает проблему интересной.

Как отметил Джеб, получение конечной части легко с помощью !str:*:=!.

Трудный бит - ведущая часть. Вот альтернатива решению jeb.

Вы можете вставить строку в переменную вместо :, используя следующий синтаксис

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

!

- ВЫВОД -

45
abc

Неверная строка выше последнего !.

Я не уверен, почему, но когда вывод вышеперечисленного передан в команду, сохраняется только первая строка. Таким образом, вывод может быть передан в FINDSTR, который соответствует любой строке, и этот результат направлен на файл, который затем может быть прочитан в переменную с помощью SET/P.

2-я строка должна быть устранена до использования 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.

Просто глядя на левую сторону команды piped, я считаю, что она разбирается (в памяти) в выражение, которое выглядит как

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", не будет распознано как внутренняя или внешняя команда, операционная программа или командный файл. кажется, просто теряется в эфире.

note - jeb 3rd comment объясняет, почему:)


Безопасная версия без 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 инвертирует результат.

Ответ 4

Да, я знаю, что это очень старая тема, но я только что ее обнаружил, и я не могу устоять перед соблазном опубликовать свое решение:

@echo off
setlocal

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

Вы можете прочитать полную информацию об этом методе здесь.

Ответ 5

Здесь решение без неприятных трюков для ведущей части

    REM accepts [email protected]
    setlocal enableDelayedExpansion
    set "str=%1"
    set "host=%str:*@=%"
    for /F "tokens=1 [email protected]" %%F IN ("%str%") do set "user=%%F"
    echo [email protected] = %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" для оставшихся "безопасных" разделяемых символов.