Extrahieren Sie Text vor, nach und innerhalb von Zeichen

574
Mark Deven

Ich habe eine Variable ( %~1) auf etwas gesetzt:Hello there this is a block: [C]Inside of Block[/C] Did you like it?

Ich möchte es in drei Variablen aufgeteilt haben:

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

Ich habe versucht, dies zu verwenden:

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

Aber es funktioniert nicht. Möglicherweise liegt dies in einem callAbschnitt, der innerhalb einer forSchleife aufgerufen wird (mit EnableDelayedExpansion). Die gesamte Zeichenfolge wird jedoch für jede Variable festgelegt. Ist das möglich?

0
Es ist mir unklar, was Sie mit Ihren Substitutionen beabsichtigen, aber wenn Sie poiseous-Zeichen wie `<> | &` verwenden, müssen Sie die ganzen Paare aus var = value in Anführungszeichen setzen -> `Set" Front =% var :, "[C]" = &:% "` (weiß nicht, für was die inneren Anführungszeichen gedacht sind). LotPings vor 5 Jahren 1
Oh, ich denke die Zitate sind Fehler. Ich werde es prüfen. Mark Deven vor 5 Jahren 0
Wenn Sie die verzögerte Erweiterung aktiviert haben, muss "%" durch "!" Ersetzt werden DavidPostill vor 5 Jahren 0
@Worthwelle: Bitte schau mal was du übersehen hast. Scott vor 5 Jahren 0
Mark Dodsons: Danke, dass Sie uns den Code gezeigt haben, den Sie geschrieben haben, aber werfen Sie uns bitte nicht einfach Code zu und sagen Sie "es funktioniert nicht." Was haben Sie aus Ihrem Debugging gelernt? (Sie haben selbst versucht, dies zu debuggen, richtig?) Bekommt `var 'den gewünschten Wert von` `% ~ 1``? Welche Werte ergeben die anderen Zuordnungen? (Die `echo`-Anweisung ist Ihr Freund.) Welche Werte erwarten Sie * von den Aufgaben? Ich verstehe sie auch nicht; Bitte erläutern Sie die Logik Ihres Codes. … (Fortsetzung) Scott vor 5 Jahren 0
Nicht wenn es ein Anruf ist Mark Deven vor 5 Jahren 0
(Fortsetzung)… Bitte antworten Sie nicht in Kommentaren. Bearbeiten Sie Ihre Frage, um sie klarer und vollständiger zu machen. Scott vor 5 Jahren 0
Ich vergaß fast zu fragen: Warum erwarten Sie nicht, `` `Hallo dort` `` `` `` `` `` `` ```````? Scott vor 5 Jahren 0
Leute, manche Leute haben keine unbegrenzte Zeit. Ich werde es selbst herausfinden, wenn es so viel Arbeit kostet. Ich versuche, all das Debuggen zu vermeiden, wenn jemand mit Erfahrung leicht etwas mit meinem Code falsch sieht, wie z. B. die Anführungszeichen, die wahrscheinlich das Problem sind. Das ist ein Teil dessen, worum es bei dieser Site geht. Wenn dem nicht so ist, dann werde ich ja Debug-Informationen und mehr hinzufügen, aber mit zwei Jobs, der High School, dem College und der Unterstützung meines alleinerziehenden Elternteils, kann ich die ganze Zeit nicht damit verbringen. Ich hatte noch keine Minute an meinem Computer, um etwas zu testen (ich bin mobil), aber sobald ich es habe, melde ich mich bei Ihnen. Mark Deven vor 5 Jahren 0
Wenn diese Website nicht damit umgehen kann, kann sie mir meistens nicht helfen. Verzeihen Sie mir, wenn ich unhöflich bin, aber die Haltung, die bei den meisten von ihnen auftritt, hat einen * extrem * urteilenden Ton. Mark Deven vor 5 Jahren 0
Die meisten Programmierer, mit denen ich zusammenarbeite, lehnen die Verwendung dieser Websites aus genau diesem Grund ab. Dies sollte dazu dienen, der Community zu helfen und nicht den wenigen Auserwählten mit der höchsten Wiederholung zu gefallen. Mark Deven vor 5 Jahren 0
Es war jedoch ein Tippfehler mit dem * Hallo dort * Text Mark Deven vor 5 Jahren 0

2 Antworten auf die Frage

3
dbenham

Ich wäre hilfreich gewesen, wenn Sie einen Link zu etwas eingefügt hätten, der die von Ihnen verwendete Technik erklärt. Zum Glück bin ich mit der Technik vertraut.

Sie versuchen, mithilfe der Variablenerweiterung Suchen / Ersetzen einen Kommentar in einen String einzufügen, sodass Sie den Anfang des Strings bis zu einem Teilstring extrahieren können. Ich bin eher mit der Verwendung vertraut REM, aber Ihre Verwendung eines :Labels als Pseudokommentar sollte ebenfalls funktionieren.

Ich zeige Ihnen kurz, wie das funktionieren kann. Ich habe ECHO ONstrategische Ziele, damit Sie sehen können, wie die Substitution funktioniert. Dies erfordert, dass ich REManstelle von verwenden, :weil Labels nicht ECHOed sind.

@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 

--AUSGABE--

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

Die zusätzlichen Leerzeichen um die &sind ein Artefakt der Art, wie cmd.exe die Zeile wiedergibt, sie werden durch das Finden / Ersetzen nicht wirklich eingeführt. Sie sollten jedoch in der Lage sein zu sehen, wie die Technik funktioniert.

Ich verstehe nicht, warum Sie Kommas und Anführungszeichen in Ihre Suchzeichenfolge eingefügt haben - sie sind nicht in Ihrer Startzeichenfolge enthalten, sodass nichts ersetzt wird.

Es ist wichtig, dass Sie Anführungszeichen verwenden, wenn Sie den Anfangswert von speichern %~1, um sich vor Giftzeichen zu schützen.

Schließlich ist es auch wichtig, Anführungszeichen in Ihren nachfolgenden Aufgaben zu haben. Das erste Anführungszeichen steht vor dem Variablennamen, und das schließende Anführungszeichen wird durch den Ersetzungsausdruck unmittelbar vor dem Variablennamen eingefügt &:.

Da Sie :stattdessen verwenden REM, ist es nicht erforderlich, nach dem Zeichen ein Leerzeichen einzufügen :.

Hier ist Arbeitscode. Beachten Sie, dass ich die varVerwendung einer zusätzlichen Variablen durch Verwendung Backder temporären Werte eliminiert habe, bis ich den endgültigen Back-Wert erhalten kann.

@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 

-- AUSGABE --

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

Beachten Sie meine Verwendung von Anführungszeichen in der Ausgabe - sie stehen nicht in den tatsächlich gespeicherten Werten. Sie werden vielmehr vom ECHO-Befehl eingeführt, um die Existenz des nachgestellten / führenden Raums zu zeigen, und sie würden auch vor Giftfiguren schützen.

Die obige Technik hat einige Einschränkungen:

  • Der %~1Wert sollte keine Anführungszeichen enthalten. Andernfalls besteht die Gefahr, dass Giftzeichen das Ergebnis beschädigen
  • Der %~1Wert darf keine Zeilenvorschub (0x0A) oder Wagenrücklauf (0x0D) enthalten.
  • Der Teil, die Sie (ersetzen [C]und [/C]in Ihrem Fall) muß beginnen, nicht mit ~, *oder %.
  • Die Teilzeichenfolgen, die Sie ersetzen, dürfen sich an keiner =Stelle befinden

Hier ist eine völlig unabhängige JREPL.BAT-Lösung

Wenn Sie gerne mit regulären Ausdrücken arbeiten, können Sie meine JREPL.BAT verwenden - ein reines Skript-Dienstprogramm (Hybrid-JScript / Batch), das nativ auf einem Windows-Computer ab XP ausgeführt wird, ohne dass eine EXE-Datei eines Drittanbieters erforderlich ist.

Die JREPL-Lösung ist für diese Anwendung etwas langsamer als die reine Stapelverarbeitung, hat jedoch zwei große Vorteile:

  • Die Logik ist klarer, solange Sie reguläre Ausdrücke verstehen
  • Es gibt keine Zeichenbeschränkungen. %~1Es kann immer noch kein Wagenrücklauf oder Zeilenvorschub enthalten. Aber eine Variable kann und JREPL wird mit diesen Zeichen gut funktionieren.

Wenn Sie nur einen einzelnen Wert extrahieren müssen, ist die Lösung sehr einfach - JREPL kann das Ergebnis in einer Umgebungsvariablen speichern. Der folgende Code erfasst den Wert in Ihrem Block:

@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 

-- AUSGABE --

Inside = "Inside of Block" 

Sie möchten jedoch 3 Werte erfassen. Sie können drei separate JREPL-Aufrufe durchführen, aber das wäre ineffizient. Im folgenden Code VariableName=füge ich an den entsprechenden Stellen Newlines ein und lasse FOR /Fdie drei Ergebnisse iterieren und speichern.

@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 

-- AUSGABE --

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

Das JREPL-Dienstprogramm enthält umfangreiche Hilfe.

  • JREPL /? wird alle Hilfe auflisten.
  • JREPL /?options wird alle verfügbaren Optionen kurz zusammenfassen
  • JREPL /?/Tdie beschreiben T ranslate Option, die ich verwendet. Sie können dasselbe für /?/XSEQund tun/?/S

Sie werden wahrscheinlich viele Anwendungen für JREPL finden, sobald Sie es in Ihrem Arsenal an Werkzeugen haben. JREPL glänzt wirklich bei der Bearbeitung von Textdateien - es ist viel schneller und leistungsfähiger als jede reine Batch-Lösung.

Ja, ich konnte nicht herausfinden, wo ich diese Logik gefunden hatte, aber ich habe ähnlichen Code in einem anderen Skript gefunden, das nicht funktioniert hat, da es Dinge erfordert, die ich nicht habe. Die Kommas und das Zeug waren übrig und ich wusste einfach nicht, was die Zeichenfolge war und was Code war. Mark Deven vor 5 Jahren 0
funktioniert das auch mit Charakteren wie:,;}? Mark Deven vor 5 Jahren 0
@ MarkDodsons - Ich habe die Einschränkungen um die Antwort erweitert und eine völlig unabhängige JREPL.BAT-Lösung hinzugefügt, die die Einschränkungen beseitigt. dbenham vor 5 Jahren 0
1
Worthwelle

Im Allgemeinen sind Batch-Dateien für die Verarbeitung derart komplexer Objekte nicht sehr effizient. Es ist auch nicht möglich, die Variablenersetzung so zu verwenden, wie Sie es versucht haben.

Allerdings sollte diese Lösung für alle Zeichenfolgen funktionieren, die einen einzelnen Block oder überhaupt keine Blöcke enthalten. Dies funktioniert nicht für mehrere Blöcke. Es wird auch nur für einzelnen Zeichenblock - Tags funktionieren (dh [C], [b], [9]). Es funktioniert auch nicht, wenn Sie [Zeichen in Ihrem Text haben, die nicht Teil von Blöcken sind.

: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 

Der SplitAufruf teilt die Zeichenfolge nach [Zeichen auf und leitet sie an den SetAnruf weiter. Der SetAufruf entfernt dann die Anfangs- und Endblock-Tags.

Lesen Sie weiter: Variable Edit / Replace - SS64