У меня есть переменная (%~1), установленная на что-то вроде: Hello there this is a block: [C]Inside of Block[/C] Did you like it?

Я хочу разделить его на три переменные:

Front=hello there this is a block: 
Block=Inside of Block
Back=Did you like it?

Я пытался использовать это:

:call
set var=%~1
set Front=%var:,"[C]"=&:%
set Back=%var:*"[/C]=%
Set var=%var:,"[/C]"=&:%
Set var=%var:*"[C]=%
set Inside=%var%

Но это не работает. Это может быть потому, что это в разделе call который вызывается из цикла for (с EnableDelayedExpansion). Но вся строка установлена для каждой переменной. Возможно ли это сделать?

2 ответа2

3

Я был бы полезен, если бы вы включили ссылку на что-то, что объясняет технику, которую вы пытаетесь использовать. К счастью, я знаком с техникой.

Вы пытаетесь использовать расширение / переменную find / replace, чтобы вставить комментарий в строку, чтобы вы могли извлечь начало строки, вплоть до некоторой подстроки. Я более знаком с использованием REM , но использование a : label в качестве псевдо-комментария также должно работать.

Я покажу быстрый пример того, как это может работать. У меня есть ECHO ON на стратегических линиях, чтобы вы могли видеть, как работает замена. Это требует, чтобы я использовал REM вместо : потому что метки не ECHOed.

@echo off
setlocal
set "var=String Before<split here>String After"
echo on
set "Before=%var:<split here>="&rem %
@set before
set "After=%var:*<split here>=%"
@set after

--ВЫХОД--

C:\test>set "Before=String Before"  & rem String After
Before=String Before

C:\test>set "After=String After"
After=String After

Лишние пробелы вокруг & являются артефактом того, как cmd.exe повторяет строку, на самом деле они не вводятся при поиске / замене. Но вы должны увидеть, как работает техника.

Я не понимаю, почему вы включили запятые и кавычки в строку поиска - их нет в вашей стартовой строке, поэтому ничего не будет заменено.

Важно использовать кавычки при сохранении начального значения %~1 чтобы защитить от ядовитых символов.

Наконец, также важно иметь кавычки в ваших последующих заданиях. Первая кавычка перед именем переменной, а закрывающая кавычка вводится термином замены, непосредственно перед &:

Поскольку вы используете : вместо REM , нет необходимости вводить пробел после :

Вот рабочий код. Обратите внимание, что я исключил необходимость в дополнительной переменной var , используя Back для временных значений, пока не буду готов получить окончательное значение Back.

@echo off
setlocal
call :extract "Hello there this is a block: [C]Inside of Block[/C] Did you like it?"
echo Front  = "%Front%"
echo Inside = "%Inside%"
echo Back   = "%Back%"
exit /b

:extract
set "Back=%~1"
set "Front=%Back:[C]="&:%
set "Back=%Back:*[C]=%"
set "Inside=%Back:[/C]="&:%
set "Back=%Back:*[/C]=%"
exit /b

-- ВЫХОД --

Front  = "Hello there this is a block: "
Inside = "Inside of Block"
Back   = " Did you like it?"

Обратите внимание на мое использование кавычек в выходных данных - они не находятся в фактических сохраненных значениях. Скорее они вводятся командой ECHO, чтобы показать существование конечного / ведущего пробела, а также защищают от ядовитых персонажей.

Вышеуказанная техника имеет несколько ограничений:

  • Значение %~1 не должно содержать кавычек, в противном случае вы рискуете отравить символы, искажающие результат
  • Значение %~1 не может содержать перевод строки (0x0A) или возврат каретки (0x0D).
  • Подстроки, которые вы заменяете ([C] и [/C] в вашем случае) не должны начинаться с ~ , * или % .
  • Подстроки, которые вы заменяете, не должны содержать = где-либо внутри них

Вот совершенно не связанное решение JREPL.BAT

Если вам нравится работать с регулярными выражениями, то вы можете использовать мой JREPL.BAT - чистую утилиту сценариев (гибридный JScript/batch), которая работает на любом компьютере с Windows начиная с XP и не требует никаких сторонних .exe-файлов.

Решение JREPL будет немного медленнее, чем чистый пакет для этого приложения, но оно имеет два больших преимущества:

  • Логика более прямолинейна, если вы понимаете регулярные выражения
  • Там нет ограничений персонажа. %~1 прежнему не может содержать возврат каретки или перевод строки. Но переменная может, и JREPL будет отлично работать с этими символами.

Если вам нужно извлечь только одно значение, тогда решение действительно простое - JREPL имеет возможность сохранить результат в переменной среды. Код ниже захватит значение внутри вашего блока:

@echo off
setlocal
call :extract "Hello there this is a block: [C]Inside of Block[/C] Did you like it?"
echo Inside = "%Inside%"
exit /b

:extract
set "Inside=%~1"
call jrepl "\[C](.*)\[/C]" "$txt=$1" /s Inside /jmatchq /rtn Inside
exit /b

-- ВЫХОД --

Inside = "Inside of Block"

Но вы хотите захватить 3 значения. Вы можете сделать три отдельных вызова JREPL, но это будет неэффективно. В приведенном ниже коде я вставляю VariableName= и символы новой строки в соответствующие места, и позволяю FOR /F повторять и сохранять три результата.

@echo off
setlocal
call :extract "Hello there this is a block: [C]Inside of Block[/C] Did you like it?"
echo Front  = "%Front%"
echo Inside = "%Inside%"
echo Back   = "%Back%"
exit /b

:extract
set "Front=%~1"
for /f "delims=" %%A in (
  'jrepl "^|\[C]|\[/C]" "Front=|\nInside=|\nBack=" /s Front /t "|" /xseq'
) do set "%%A"
exit /b

-- ВЫХОД --

Front  = "Hello there this is a block: "
Inside = "Inside of Block"
Back   = " Did you like it?"

Обширная справка встроена в утилиту JREPL.

  • JREPL /? перечислю всю помощь.
  • JREPL /?options будут кратко обобщать все доступные варианты
  • JREPL /?/T опишет опцию T ranslate, которую я использовал. Вы можете сделать то же самое для /?/XSEQ и /?/S

Скорее всего, вы найдете множество вариантов использования JREPL, когда они появятся в вашем арсенале инструментов. JREPL действительно великолепен, когда дело доходит до манипулирования текстовыми файлами - он намного быстрее и мощнее, чем любое чистое пакетное решение.

1

В общем, командные файлы не очень эффективны для обработки сложных вещей, подобных этой. Также невозможно использовать замену переменных так, как вы пытались.

При этом это решение должно работать для любых строк, которые содержат один блок или вообще не содержат блоков. Это не будет работать для нескольких блоков. Она также будет работать только для блочных тегов одного персонажа (то есть [C] , [b] , [9]). Это также не будет работать, если в вашем тексте есть [ символы, которые не являются частью блоков.

:Split
for /f "delims=[ tokens=1-3" %%a IN ("%~1") DO (
    CALL:Set "%%~a" "%%~b" "%%~c"
)
GOTO:EOF

:Set
SET Front=%~1
SET Inside=%~2
SET Back=%~3
SET Block=

IF NOT "%Inside%"=="" (
    SET Block=%Inside:~0,1%
    SET Inside=%Inside:~2%
)
IF NOT "%Back%"=="" (
    SET Back=%Back:~3%
)
GOTO:EOF

Вызов Split разделит строку на символ [ и передаст ее в вызов Set . Затем вызов Set удалит начальный и конечный теги блоков.

Дополнительное чтение: Переменная Редактировать / Заменить - SS64

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .