Извлечь текст из перед, после и внутри символов

У меня есть переменная (%~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 ответа

Решение

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

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

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

@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 опишу вариант перевода, который я использовал. Вы можете сделать то же самое для /?/XSEQ а также /?/S

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

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

При этом это решение должно работать для любых строк, которые содержат один блок или вообще не содержат блоков. Это не будет работать для нескольких блоков. Это также будет работать только для одно-символьных блочных тегов (т.е. [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 call затем удалит начальный и конечный теги блоков.

Дополнительное чтение: Переменная Edit/Replace - SS64

Другие вопросы по тегам