Wyodrębnij tekst przed, po i wewnątrz znaków


0

Mam zmienną ( %~1) ustawioną na coś takiego:Hello there this is a block: [C]Inside of Block[/C] Did you like it?

Chcę go podzielić na trzy zmienne:

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

Próbowałem użyć tego:

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

Ale to nie działa. Może być tak, ponieważ jest to callsekcja wywoływana z wnętrza forpętli (z EnableDelayedExpansion). Ale cały ciąg jest ustawiony na każdą zmienną. Czy to się da zrobić?


1
Nie jest dla mnie jasne, co zamierzasz zrobić z podstawieniami, ale jeśli używasz poisenoustakich znaków <>|&, będziesz musiał zawrzeć cały zestaw par var = wartość w podwójnych cudzysłowach -> Set "Front=%var:,"[C]"=&:%"(nie wiem, do czego służą wewnętrzne podwójne cudzysłowy).
LotPings,

Och, myślę, że cytaty to błędy. Ja sprawdzę.
Mark Deven,

Jeśli masz włączone opóźnione rozszerzenie, musisz %je zastąpić!
DavidPostill

@Worthwelle: Proszę spojrzeć i zobaczyć, co przeoczyliście.
Scott

Mark Dodsons: Dzięki za pokazanie nam kod został napisany, ale proszę, nie tylko rzucać kod na nas i powiedzieć „to nie działa”. Co jest ona robi? Czego nauczyłeś się podczas debugowania? (Próbowałeś samodzielnie debugować, prawda?) Czy varotrzymujesz pożądaną wartość %~1? Jakie wartości przynoszą inne zadania? ( echoOświadczenie jest twoim przyjacielem.) W związku z tym, jakich wartości oczekujesz od zadań? Też ich nie rozumiem; wyjaśnij logikę swojego kodu. … (Ciąg dalszy)
Scott

Odpowiedzi:


3

Byłbym pomocny, gdybyś zamieścił link do czegoś, co wyjaśnia technikę, której próbujesz użyć. Na szczęście znam tę technikę.

Próbujesz użyć rozwinięcia zmiennej find / replace, aby wstawić komentarz do łańcucha, abyś mógł wyodrębnić początek łańcucha, aż do jakiegoś podłańcucha. Jestem bardziej zaznajomiony z używaniem REM, ale twoje użycie :etykiety jako pseudo komentarza również powinno działać.

Pokażę szybki przykład, jak to może działać. Mam ECHO ONna liniach strategicznych, abyś mógł zobaczyć, jak działa podstawienie. Wymaga to użycia REMzamiast, :ponieważ etykiety nie są 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

--WYDAJNOŚĆ--

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

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

Dodatkowe spacje wokół &są artefaktem tego, jak cmd.exe echa linii, tak naprawdę nie są wprowadzane przez find / replace. Ale powinieneś być w stanie zobaczyć, jak działa ta technika.

Nie rozumiem, dlaczego umieściłeś przecinki i cytaty w ciągu wyszukiwania - nie ma ich w ciągu początkowym, więc nic nie zostanie zastąpione.

Ważne jest, aby używać cudzysłowów podczas zapisywania wartości początkowej, %~1aby zabezpieczyć się przed zatrutymi postaciami.

Wreszcie kluczowe znaczenie mają cytaty w kolejnych zadaniach. Pierwszy cytat znajduje się przed nazwą zmiennej, a cytat zamykający jest wprowadzany przez termin zastępujący, tuż przed &:.

Ponieważ używasz :zamiast REM, nie ma potrzeby wprowadzania spacji po :.

Oto działający kod. Zauważ, że wyeliminowałem potrzebę dodatkowej varzmiennej, używając Backwartości tymczasowych, dopóki nie będę gotowy, aby uzyskać ostateczną wartość Wstecz.

@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

- WYDAJNOŚĆ -

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

Zwróć uwagę na moje użycie cudzysłowów w danych wyjściowych - nie są one w rzeczywistych zapisanych wartościach. Są one raczej wprowadzane przez komendę ECHO, aby pokazać istnienie spływu / wiodącej przestrzeni, a także chroniłyby przed zatrutymi postaciami.

Powyższa technika ma kilka ograniczeń:

  • %~1Wartość nie powinna zawierać żadnych cytatów, inaczej ryzykujesz znaków zatruć zgorszenie wynik
  • %~1Wartość ta może zawierać linia (0x0A) lub powrotu karetki (0x0d).
  • Podciągów że wymieniasz ( [C]i [/C]w danym przypadku) nie musi zaczynać się ~, *lub %.
  • Podciągi, które zastępujesz, nie mogą zawierać =nigdzie w nich

Oto całkowicie niepowiązane rozwiązanie JREPL.BAT

Jeśli lubisz pracować z wyrażeniami regularnymi, możesz użyć mojego JREPL.BAT - czystego narzędzia skryptowego (hybrydowy JScript / partia), które działa natywnie na dowolnym komputerze z systemem Windows od XP, nie potrzebujesz żadnego pliku .exe innej firmy.

Rozwiązanie JREPL będzie nieco wolniejsze niż czysta partia dla tej aplikacji, ale ma dwie duże zalety:

  • Logika jest bardziej prosta, o ile rozumiesz wyrażenia regularne
  • Nie ma limitów postaci. %~1nadal nie może zawierać powrotu karetki ani podawania wiersza. Ale zmienna może i JREPL będzie działać dobrze z tymi znakami.

Jeśli potrzebujesz tylko wyodrębnić jedną wartość, rozwiązanie jest naprawdę proste - JREPL ma możliwość przechowywania wyniku w zmiennej środowiskowej. Poniższy kod uchwyci wartość wewnątrz twojego bloku:

@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

- WYDAJNOŚĆ -

Inside = "Inside of Block"

Ale chcesz uchwycić 3 wartości. Możesz wykonać trzy osobne wywołania JREPL, ale byłoby to nieefektywne. W poniższym kodzie wstawiam VariableName=i nowe wiersze w odpowiednich miejscach oraz pozwalam FOR /Fiterować i przechowywać trzy wyniki.

@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

- WYDAJNOŚĆ -

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

Obszerna pomoc jest wbudowana w narzędzie JREPL.

  • JREPL /? wyświetli całą pomoc.
  • JREPL /?options krótko podsumuje wszystkie dostępne opcje
  • JREPL /?/Topisze T opcję ranslate że użyłem. Możesz zrobić to samo dla /?/XSEQi/?/S

Prawdopodobnie znajdziesz wiele zastosowań JREPL, gdy już znajdziesz je w swoim arsenale narzędzi. JREPL naprawdę błyszczy, gdy chodzi o manipulowanie plikami tekstowymi - jest o wiele szybszy i potężniejszy niż każde czyste rozwiązanie wsadowe.


Tak, nie byłem w stanie znaleźć, skąd wziąłem tę logikę, ale znalazłem podobny kod w innym skrypcie, który nie działał, ponieważ wymagał rzeczy, których nie mam. Przecinki i inne rzeczy pozostały, a ja po prostu nie wiedziałem, co to jest łańcuch, a co kod.
Mark Deven,

czy to zadziała nawet z postaciami takimi jak:,;}?
Mark Deven,

@MarkDodsons - dodałem ograniczenia do odpowiedzi i dodałem całkowicie niezwiązane rozwiązanie JREPL.BAT, które usuwa ograniczenia.
dbenham

1

Zasadniczo pliki wsadowe nie są bardzo wydajne w przetwarzaniu takich skomplikowanych rzeczy. Nie jest również możliwe użycie zamiany zmiennych tak, jak próbowałeś.

To powiedziawszy, to rozwiązanie powinno działać dla wszystkich ciągów zawierających pojedynczy blok lub nie zawierających żadnych bloków. To nie zadziała dla wielu bloków. Będzie również działać tylko dla pojedynczego znaku znaczników blokowych (czyli [C], [b], [9]). To również nie zadziała, jeśli masz [w tekście znaki, które nie są częścią bloków.

: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

SplitPołączenie zostanie podzielona przez ciąg [znaków i przekazać do Setrozmowy. SetPołączenie zostanie następnie usunąć znaczniki początku i końca bloku.

Dalsza lektura: Zmienna edycja / zamiana - SS64

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.