Extrai texto da frente, depois e dentro dos caracteres

0

Eu tenho uma variável ( %~1 ) definida para algo como: Hello there this is a block: [C]Inside of Block[/C] Did you like it?

Eu quero separar em três variáveis:

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

Eu tentei usar isso:

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

Mas não está funcionando. Pode ser porque isso está em uma seção call que está sendo chamada de dentro de um loop for (com EnableDelayedExpansion). Mas a string inteira é definida para cada variável. Isso é possível fazer?

    
por Mark Deven 02.10.2018 / 18:46

2 respostas

3

Eu teria sido útil se você tivesse incluído um link para algo que explica a técnica que você está tentando usar. Felizmente, estou familiarizado com a técnica.

Você está tentando usar a localização / substituição de expansão de variável para injetar um comentário em uma sequência de caracteres para que você possa extrair o início da cadeia, até uma subseqüência de caracteres. Estou mais familiarizado com o uso de REM , mas o uso de um rótulo : como um pseudo comentário também deve funcionar.

Mostrarei um exemplo rápido de como isso pode funcionar. Eu tenho ECHO ON em linhas estratégicas para que você possa ver como a substituição funciona. Isso requer que eu use REM em vez de : porque os rótulos não são ECO.

@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

- OUTPUT -

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

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

Os espaços extras ao redor do & são um artefato de como o cmd.exe ecoa a linha, eles não são realmente introduzidos pelo localizar / substituir. Mas você deve ser capaz de ver como a técnica funciona.

Eu não entendo por que você incluiu vírgulas e citações em sua string de pesquisa - elas não estão lá na sua string inicial, então nada será substituído.

É importante que você use aspas ao salvar o valor inicial de %~1 para proteger contra caracteres suspeitos.

Finalmente, também é importante ter cotações em suas atribuições subsequentes. A primeira cotação é anterior ao nome da variável, e a cotação de fechamento é injetada pelo termo de substituição, logo antes do &: .

Como você está usando : em vez de REM , não é necessário introduzir um espaço após o : .

Aqui está o código de trabalho. Observe que eliminei a necessidade de uma variável var extra usando Back para os valores temporários até que eu esteja pronto para obter o valor final de 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

- OUTPUT -

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

Observe meu uso de aspas na saída - elas não estão nos valores reais armazenados. Em vez disso, eles são introduzidos pelo comando ECHO para mostrar a existência do espaço à esquerda / líder, e também protegem contra caracteres envenenados.

A técnica acima tem algumas restrições:

  • O valor %~1 não deve conter aspas, senão você corre o risco de caracteres envenenados que corrompem o resultado
  • O valor %~1 não pode conter nova linha (0x0A) nem retorno de carro (0x0D).
  • As subseqüências que você está substituindo ( [C] e [/C] no seu caso) não devem começar com ~ , * ou % .
  • As subseqüências que você está substituindo não devem conter = em qualquer lugar dentro delas

Aqui está uma solução JREPL.BAT totalmente não relacionada

Se você gosta de trabalhar com expressões regulares, pode usar meu JREPL.BAT - um utilitário de script puro (JScript / batch híbrido) executado nativamente em qualquer máquina Windows do XP em diante, sem necessidade de nenhum arquivo .exe de terceiros.

A solução JREPL será um pouco mais lenta que o lote puro para esta aplicação, mas tem duas grandes vantagens:

  • A lógica é mais direta, desde que você entenda expressões regulares
  • Não há limites de caracteres. %~1 ainda não pode conter retorno de carro ou alimentação de linha. Mas uma variável pode, e o JREPL funcionará bem com esses caracteres.

Se você só precisa extrair um único valor, a solução é realmente simples - o JREPL tem a capacidade de armazenar o resultado em uma variável de ambiente. O código abaixo irá capturar o valor dentro do seu bloco:

@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

- OUTPUT -

Inside = "Inside of Block"

Mas você quer capturar 3 valores. Você poderia fazer três chamadas JREPL separadas, mas isso seria ineficiente. No código abaixo eu insiro VariableName= e newlines nos locais apropriados e deixo FOR /F iterar e armazenar os três resultados.

@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

- OUTPUT -

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

Extensa ajuda está embutida no utilitário JREPL.

  • JREPL /? listará toda a ajuda.
  • JREPL /?options resumirá brevemente todas as opções disponíveis
  • JREPL /?/T descreverá a opção de conversão T que usei. Você pode fazer o mesmo para /?/XSEQ e /?/S

Você provavelmente encontrará muitos usos para o JREPL, uma vez que o tenha em seu arsenal de ferramentas. O JREPL realmente brilha quando se trata de manipular arquivos de texto - é muito mais rápido e mais poderoso do que qualquer solução de lote puro.

    
por 02.10.2018 / 23:12
1

Em geral, os arquivos em lote não são muito eficientes para processar coisas complexas como essa. Também não é possível usar a substituição de variáveis do jeito que você tentou.

Dito isto, esta solução deve funcionar para qualquer string que contenha um único bloco ou não contenha nenhum bloco. Isso não funcionará para vários blocos. Ele também funcionará apenas para tags de bloco de caractere único (por exemplo, [C] , [b] , [9] ). Também não funcionará se você tiver [ caracteres em seu texto que não fazem parte de blocos.

: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

A chamada Split dividirá a string pelo caractere [ e passará isso para a chamada Set . A chamada Set removerá as tags de bloco inicial e final.

Outras leituras: Editar / substituir variável - SS64

    
por 02.10.2018 / 22:34