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

312
Mark Deven

У меня есть переменная ( %~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). Но вся строка установлена ​​для каждой переменной. Возможно ли это сделать?

0
Мне непонятно, что вы собираетесь делать с подстановками, но если вы используете символы `poisenous`, такие как` <> | & `, вам придется заключать в двойные кавычки целые пары set var = value ->` Set "Front =% var :, "[C]" = &:% "` (не знаю, для чего предназначены внутренние двойные кавычки). LotPings 5 лет назад 1
О, я думаю, что цитаты являются ошибками. Я проверю. Mark Deven 5 лет назад 0
Если вы включили отложенное расширение, то `%` необходимо заменить на `!` DavidPostill 5 лет назад 0
@Worthwelle: Пожалуйста, посмотрите и посмотрите, что вы упустили. Scott 5 лет назад 0
Марк Додсонс: Спасибо, что показали нам код, который вы написали, но, пожалуйста, не бросайте нам код и говорите: «Это не работает». Что *** делает ***? Что вы узнали из своей отладки? (Вы пытались отладить это самостоятельно, верно?) Получает ли `var` желаемое значение из` `% ~ 1``? Какие значения дают другие назначения? (Выражение `echo` - ваш друг.) В таком случае, какие значения вы * ожидаете получить от назначений? Я тоже их не понимаю; Пожалуйста, объясните логику вашего кода. … (Продолжение) Scott 5 лет назад 0
Не когда это звонок Mark Deven 5 лет назад 0
(Продолжение)… Пожалуйста, не отвечайте в комментариях; [отредактируйте] ваш вопрос, чтобы сделать его более понятным и полным. Scott 5 лет назад 0
О, я почти забыл спросить: почему * вы * не ожидаете (не хотите) получить `` `Hello there`` `в" Front "? Scott 5 лет назад 0
Ребята, у некоторых людей нет неограниченного времени. Я пойму это сам, если это займет так много работы. Я пытаюсь избежать всей отладки, если кто-то с опытом может легко увидеть что-то не так с моим кодом, например, кавычки, которые, вероятно, являются проблемой. Это часть того, что представляет собой этот сайт. Если это не так, тогда да, я добавлю отладочную информацию и многое другое, но с двумя работами, средней школой, колледжем и помогая моему одинокому родителю, я не могу тратить все это время на это. У меня еще не было минуты на моем компьютере, чтобы что-то тестировать (я на мобильном), но как только у меня будет время, я перезвоню вам Mark Deven 5 лет назад 0
Если этот сайт не может справиться с этим, то это не то, что может помочь мне большую часть времени. Простите, если я выгляжу грубым, но отношение, которое проявляется в большинстве из них, имеет * чрезвычайно * осуждающий тон. Mark Deven 5 лет назад 0
Большинство программистов, с которыми я работаю, отказываются использовать эти сайты именно по этой причине. Это должно быть для того, чтобы помогать сообществу, а не радовать избранных с самой высокой репутацией. Mark Deven 5 лет назад 0
Тем не менее, это была опечатка с * привет там * текст Mark Deven 5 лет назад 0

2 ответа на вопрос

3
dbenham

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

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

Я покажу быстрый пример того, как это может работать. У меня есть 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 действительно великолепен, когда дело доходит до манипулирования текстовыми файлами - он намного быстрее и мощнее, чем любое чистое пакетное решение.

Да, я не смог найти, откуда у меня появилась эта логика, но я нашел похожий код в другом скрипте, который не работал, так как требовал того, чего у меня нет. Запятые и прочее остались, и я просто не знал, что это за строка, а что за код. Mark Deven 5 лет назад 0
это будет работать даже с такими символами, как:,;}? Mark Deven 5 лет назад 0
@MarkDodsons - я добавил ограничения к ответу и добавил совершенно не связанное решение JREPL.BAT, которое снимает ограничения. dbenham 5 лет назад 0
1
Worthwelle

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

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