peter8810
Goto Top

Textblöcke aus Quelldatei filtern und in neue Datei schreiben

Hallo liebe Admins!

Mein Problem ist, das ich nicht weiss wie ich eine .txt Datei so zerfilter oder absuche, dass ich genau den Bereich an Text rausbekomme, den ich gerne haben möchte (also ein von-da-bis-da-Problem).
Hier mein Beispieltext (beispiel.txt):

//---- test() ------------------//
// 1. kommentarzeile            //
// 2. kommentarzeile            //
//------------------------------//
proc test()
/****************************************************/
/* BLABLA zu proc test()                            */
/****************************************************/
//---- test2(parameter1, parameter2) ----//
// 1. kommentarzeile            //
// 2. kommentarzeile            //
//------------------------------//
proc test2(parameter1, parameter2)
/****************************************************/
/* BLABLA ZU proc test2(parameter1, parameter2)     */
/****************************************************/
//--------------------------------//
// zwischendrin steht unwichtiges //
// das will ich nicht haben       //
//--------------------------------//
//---- test3() -------------------//
// 1. kommentarzeile              //
// 2. kommentarzeile              //
//--------------------------------//
proc test3zusatz()
/****************************************************/
/* BLABLA ZU proc test3zusatz()                     */
/****************************************************/
//____________________
//     test4()
//____________________
// 1. kommentarzeile
// 2. kommentarzeile
//____________________
template test4()

Ich möchte den Text von Zeile 1-4, 9-12 usw haben, jedoch nicht den von 17-20.

Im Beispiel hier sind immer nur 2 Kommentarzeilen, aber ich habe auch größere Bereiche (die vorher unbekannt sind). Also kann ich auch nicht einfach nach test1() etc. suchen und dann sagen die nächsten 3 Zeilen noch mitnehmen.

Wie könnte man das mit Batch lösen?

Hoffentlich kann mir jemand helfen.

Liebe Grüße

Content-Key: 147176

Url: https://administrator.de/contentid/147176

Printed on: April 19, 2024 at 16:04 o'clock

Member: bastla
bastla Jul 19, 2010 at 13:16:40 (UTC)
Goto Top
Hallo peter8810 und willkommen im Forum!

Die Anweisung "Filtere alle Zeilen, die mit "//" beginnen" wäre in Batch ja einfach umzusetzen:
findstr /b "\/\/" Beispiel.txt
- aber woran ist konkret Beginn und Ende eines Blocks mit "unwichtigen" Zeilen zu erkennen?

Grüße
bastla
Member: peter8810
peter8810 Jul 19, 2010 at 13:35:04 (UTC)
Goto Top
Hallo bastla!

Danke für die schnelle Rückmeldung und die freundliche Aufnahme!

Also: Wichtige Blöcke sind diese:

//---- test() ------------------//
// 1. kommentarzeile            //
// 2. kommentarzeile            //
//------------------------------//
proc test()

Beginnend mit 2 Slash + 4 Bindestrichen + einem Leerzeichen + Text
bis
2 Slash + bestimmte Anzahl an Bindestrichen + 2 Slash

das "proc Text" befindet sich immer am Ende eines solchen Blocks und ich dachte mir das ich damit irgendwie einen Filter bauen kann, der genau von:

"//---- Text  
...
bis
...
proc Text"  

geht. Ich bekomm mit 'findstr' immer nur eine komplette Analyse der Quelldatei hin. Also kein fange an zu suchen bei Muster1 (//----) bis Muster2 (proc ).

Bisschen kompliziert, hoffentlich kommt rüber was ich meine! face-smile

Grüße
peter8810

Edit: unwichtige Blöcke bzw. Teile sind halt der Rest. Hab falsch gelesen und andersrum geantwortet!
Member: bastla
bastla Jul 19, 2010 at 13:56:19 (UTC)
Goto Top
Hallo peter8810!

Unter der Voraussetzung, dass es immer definierte Blöcke mit Beginn %Von% (inklusive) und Ende %Bis% (exklusive) - wie in den Zeilen 4 und 5 festgelegt - gibt und keine Sonderzeichen "<|>&" enthalten sind, versuch es mal so:
@echo off & setlocal
set "Ein=Beispiel.txt"  
set "Aus=Gefiltert.txt"  
set "Von=//---- "  
set "Bis=proc"  

del "%Aus%" 2>nul  
set "Schreiben="  
for /f "tokens=1* delims=:" %%i in ('findstr /n "^" "%Ein%"') do call :ProcessLine "%%j"  
goto :eof

:ProcessLine
echo\%~1|findstr /b /c:"%Von%">nul && set "Schreiben=True"  
echo\%~1|findstr /b /c:"%Bis%">nul && set "Schreiben="  
if defined Schreiben >>"%Aus%" echo\%~1  
goto :eof
In den Zeilen 2 und 3 können natürlich auch komplette Dateipfade verwendet werden. Falls auch die Zeile mit der %Bis%-Markierung noch geschrieben werden soll, die Zeilen 14 und 15 vertauschen.

Die verwendete Technik: Abhängig vom Zustand des "Schalters" %Schreiben% (gesetzt oder leer = "not defined") wird jede einzelne Zeile in die Zieldatei geschrieben, wobei ab einer Zeile, die mit dem in %Von% festgelegten String beginnt das Schreiben "eingeschaltet" und ab einer mit "%Bis%" beginnenden Zeile das Schreiben wieder "ausgeschaltet" wird.

Nach dem gleichen Prinzip, aber ohne Unterprogramm sähe das dann so aus:
@echo off & setlocal
set "Ein=Beispiel.txt"  
set "Aus=Gefiltert.txt"  
set "Von=//---- "  
set "Bis=proc"  

del "%Aus%" 2>nul  
set "Schreiben="  
for /f "tokens=1* delims=:" %%i in ('findstr /n "^" "%Ein%"') do (  
    echo\%%j|findstr /b /c:"%Von%">nul && set "Schreiben=True"  
    echo\%%j|findstr /b /c:"%Bis%">nul && set "Schreiben="  
    if defined Schreiben echo\%%j
)>>"%Aus%"  
[Edit] Mit "echo\" durchgängig für Leerzeilen vorgesorgt [/Edit]

Grüße
bastla
Mitglied: 77559
77559 Jul 19, 2010 at 14:27:03 (UTC)
Goto Top
Hallo bastla,
ich mag mich täuschen, aber bei deiner Version kommt doch die proc-Zeile nicht mit raus?

Du warst schneller, meine Version sah ähnluch aus.

:: Peter8810.cmd::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: LotPings  administrator.de 2010-07-19
@echo off & Setlocal 
Set Inp="Input.txt"  
Set Out="output.txt"  
If defined Flag Set "Flag="  
For /f "usebackq delims=" %%A in (%Inp%) Do Set "Line=%%A" & Call :ProcLine  
Goto :eof
:ProcLine
Echo.%Line%| Findstr "^//-*.*(.*).-*//$" >NUL 2>&1 && Set Flag=Ok  
If not defined Flag goto :Eof
>>%Out% Echo.%Line%
If /I "%Line:~0,4%" EQU "proc" Set "Flag="  

Gruß
LotPings

Edit: damit ich nicht noch mehr Beulen von Bibers Doku-Keule kriege:
  • Die For Schleife verarbeitet alle Zeilen und gibt sie an die Sub ProcLine in der Variable Line weiter.
  • Die Zeile 10 stellt über eine RegularExpression fest, ob die Startbedingung gegeben ist und setzt die Var Flag
  • solange Flag gesetzt ist werden die Zeilen ausgegeben
  • wenn die ersten 4 Zeichen "proc" enthalten wird Flag zurückgesetzt.
*
Member: bastla
bastla Jul 19, 2010 at 15:01:13 (UTC)
Goto Top
Hallo LotPings!
ich mag mich täuschen, aber bei deiner Version kommt doch die proc-Zeile nicht mit raus?
Hatte es zunächst so verstanden (und bin mir noch immer nicht ganz sicher), dass sie das auch nicht sollte, und dann nur beiläufig nachgereicht (durch Vertauschen der Zeilen zum Flag-Rücksetzen und Schreiben - in der ersten Version Zeilen 14 und 15 - wird auch die %Bis%-Zeile noch geschrieben) ...

Grüße
bastla
Member: peter8810
peter8810 Jul 20, 2010 at 06:48:55 (UTC)
Goto Top
Hallo ihr beiden!

Ohne Witz: erstmal Respekt wie schnell ihr was hingezaubert habt! Vielen Dank!

Also momentan probiere ich den Code von bastla und muss feststellen das mein Zielordner mit jeder Menge Dateien gefüllt wird! Alles so kleine Fragmente der Quelldatei ohne Dateiendung und meist leer oder 2-3 Wörter der Quelldatei :D
Keine Ahnung warum. Im cmd kommen tausend Fehlermeldungen like: "kann Pfad nicht finden", "Syntaxfehler", "'xy' ist syntaktisch nicht verarbeitbar", "Befehl konnte nicht gefunden werden", etc.

Ich denke das liegt an der Quelldatei, da auch "=", "<", ">", "|", usw. vorkommen. Da muss ich mir noch was überlegen. Hätte auch schon eine Idee. Und zwar das ich vorher den Text umwandel, oder besser gesagt: für jedes "=" ein "xgleichx" (oder was anderes) hinschreibe (per batch oder so). Halt das Sonderzeichen durch Text/Buchstaben ausgetauscht werden und hinterher wieder zurück gewandelt werden damit es da keine Fehler gibt.

Mir gefällt deine Idee mit dem "schreiben" = true oder false. Ich glaub damit kann ich was anfangen. Blöd das ich nicht auf sowas komme!

Der Code von LotPings wirft keine Fehlermeldung auf den Bildschirm, allerdings passiert auch sonst nichts. Komisch! Das Skript startet, es dauert einen moment und dann beendet sich das cmd-Fenster. Ich habe lediglich bei Input und Output meine Datei angegeben und die Ausgabedatei.

Auch wenn es noch nicht ganz funktioniert hilft mir das schonmal super weiter.

Grüße
peter8810
Mitglied: 77559
77559 Jul 20, 2010 at 10:14:56 (UTC)
Goto Top
Hallo Peter,

vorausgesetzt die Kommentare enthalten keine Sonderzeichen, sollte dies funktionieren

:: Peter8810.cmd::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: LotPings  administrator.de 2010-07-19
@echo off & Setlocal 
Set Inp="Input.txt"  
Set Out="output.txt"  
Type NUL >%Out%
If defined Flag Set "Flag="  
For /f "delims=" %%A in (  
  'Findstr /I "^//.*//$ ^proc" %Inp%'  
    ) Do Set "Line=%%A" & Call :ProcLine  
Pause
Goto :eof
:ProcLine
Echo.%Line%| Findstr "^//-*.*(.*).-*//$" >NUL 2>&1 && Set Flag=Ok  
If not defined Flag goto :Eof
        Echo.%Line%
>>%Out% Echo.%Line%
If /I "%Line:~0,4%" EQU "proc" Set "Flag="  

Mein Batch hatte keinen sichtbaren output, sondern schreibt nur in die per Out referenzierte Datei, hab ich geändert mit einer Pause.

Gruß
LotPings
Member: peter8810
peter8810 Jul 20, 2010 at 10:57:18 (UTC)
Goto Top
Hi LotPings!

Danke für die Rückmeldung. Also dein Code funktioniert super solange keine Sonderzeichen vorkommen (wie du ja erwähnt hast). Leider kommen recht häufig welche vor... -_-

Dachte ja das man die ganz einfach durch Wörter ersetzen kann, aber das is doch alles komplizierter als ich mir das vorgestellt hab.
Wollte das so machen, dass Sonderzeichen (wie hier '|', '"')

//---- test() ------------------//
// 1. kommentarzeile            //
// 2. kommentarzeile            //
// Text | Text "Text"           // 
//------------------------------//

vorher durch Platzhalter "ersetzt" werden, die von der Batch dann auch normal verarbeitet werden können. Also:

//---- test() ------------------//
// 1. kommentarzeile            //
// 2. kommentarzeile            //
// Text XSENKRECHTERSTRICHX Text XANFUEHRUNGSZEICHENXTextXANFUEHRUNGSZEICHENX           //
//------------------------------//

Und am Ende dann wiederherstellen zu den Ausgangszeichen. Dann würde doch auch kein Fehler entstehen wenn man deinen Code benutzt, oder?

Hab da was gefunden:

set var=test
echo %var:t=r%

Ergebins: resr

So in etwa nur im großen Stil versteht sich :D Bin noch am googlen und lesen, um es hinzubekommen. Hab da auch Probleme bei der FOR-Schleife in Batch. Wenn ich Variablen habe, die in der FOR-Schleife stehen, verändern sich diese nicht. Und bei echo %var% kommt nur raus "ECHO ist ausgeschaltet (off)". Damit das klappt muss ich doch nur am Anfang der Batch zum "@echo off" das "& setlocal" hinzufügen, oder brauch ich noch mehr, damit sich die Variable verändert?

Fragen über Fragen

Grüße
peter8810

P.S.: Bei deinem ersten Code ist überhaupt nichts passiert. Damit meinte ich auch das nichtmal eine Datei erstellt worden ist. Was mich halt schon gewundert hat, weil wenigstens eine leere Datei hätte erstellt werden müssen.
Mitglied: 77559
77559 Jul 20, 2010 at 11:20:44 (UTC)
Goto Top
Zitat von @peter8810:
So in etwa nur im großen Stil versteht sich :D Bin noch am googlen und lesen, um es hinzubekommen. Hab da auch Probleme bei
der FOR-Schleife in Batch. Wenn ich Variablen habe, die in der FOR-Schleife stehen, verändern sich diese nicht. Und bei echo
%var% kommt nur raus "ECHO ist ausgeschaltet (off)". Damit das klappt muss ich doch nur am Anfang der Batch zum
"@echo off" das "& setlocal" hinzufügen, oder brauch ich noch mehr, damit sich die Variable
verändert?
  • Wenn du mit Echo eine leere Variable ausgibst, interpretiert echo das als Aufforderung seinen Status auszugeben,
das kannst du mit {Echo.%LeereVar%} verhindern, dann kommt eine leere Zeile (statt Punkt gehen auch andere Sonderzeichen als Befeheltrenner)
  • Das Variablen in geklammerten Bereichen nicht aktualisiert werden fällt unter das lange Thema "DelayedExpansion" kann man mit SetLocal EnableDelayedExpansion und Benutzung von ! statt des % oder einem Pseudo Call mit verdoppelten %-Zeichen oder durch die Benutzung von Subs umgehen ( wie in meinem Batch)

P.S.: Bei deinem ersten Code ist überhaupt nichts passiert. Damit meinte ich auch das nichtmal eine Datei erstellt worden
ist. Was mich halt schon gewundert hat, weil wenigstens eine leere Datei hätte erstellt werden müssen.
Sehe ich auch so, zumal es hier mit deinem Beispiel-Text und auch mit Sonderzeichen (aber nicht im Kommentar) funktioniert hat.

Diese Version kommt zumindest auch mit <|> in Kommentaren klar:
:: Peter8810.cmd::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: LotPings  administrator.de 2010-07-19
@echo off & Setlocal 
Set Inp="Input.txt"  
Set Out="output.txt"  
Type NUL >%Out%
If defined Flag Set "Flag="  
For /f "delims=" %%A in (  
  'Findstr /I "^//.*//$ ^proc" %Inp%'  
    ) Do Set "Line=%%A" & Call :ProcLine  
Pause
Goto :eof
:ProcLine
Echo."%Line%"| Findstr "^.//-*.*(.*).-*//.$" >NUL 2>&1 && Set Flag=Ok  
If not defined Flag goto :Eof
Set "Line=%Line:|=^|%"  
Set "Line=%Line:<=^<%"  
Set "Line=%Line:>=^>%"  
        Echo.%Line%
>>%Out% Echo.%Line%
If /I "%Line:~0,4%" EQU "proc" Set "Flag="  

Gruß
LotPings
Member: peter8810
peter8810 Jul 20, 2010 at 13:17:56 (UTC)
Goto Top
Hiho,

der Code funktioniert super! Blöcke mit "//---- Text ... bis ... proc Text" werden rausgefiltert und in eine neue Datei geschrieben. Manchmal klappt es noch nicht ganz, aber das liegt an der Formatierung und den Sonderzeichen im Text. Da werd ich mir noch was ausdenken müssen.

Ein paar Fragen hab ich noch:

Zeile 8: In der For-Schleife wird die Inputdatei mit findstr durchsucht, richtig? Wird dann jede gefundene Zeile weitergegeben (mit dem Call) oder wie funktioniert das?
Zeile 14: Hier wird gesagt, das alles folgende geschrieben werden soll? Was bedeutet: >NUL 2>&1?

Vielen Dank für die Top Hilfe! face-smile
Mitglied: 77559
77559 Jul 20, 2010 at 15:29:13 (UTC)
Goto Top
Zitat von @peter8810:
der Code funktioniert super! Blöcke mit "---- Text ... bis ... proc Text" werden rausgefiltert
Schön wenn es klappt.
Das Flag wird gesetzt wenn eine Zeile mit
- anfängt und irgendwas Klammer auf irgendwas Klammer zu, beliebige Anzahl - und // folgt.
Zurückgesetzt nach einer Zeile diemit proc beginnt.

%<---->%
Ein paar Fragen hab ich noch:

Zeile 8: In der For-Schleife wird die Inputdatei mit findstr durchsucht, richtig?
Wird dann jede gefundene Zeile weitergegeben (mit dem Call) oder wie funktioniert das?
Ja, durch die Einklammerung in ' wird die Ausgabe des Findstring Befehls Zeile für Zeile an den Do Teil weitergereicht.
Einzelheiten kriegst du mit For /? aber das musst du dir mehrmals zu Gemüte führen bis es Sinn ergibt.

Zeile 14: Hier wird gesagt, das alles folgende geschrieben werden soll?
Wie oben erwähnt wird das Flag gesetztm ab jetzt beachten.
Was bedeutet: >NUL 2>&1?
Da diese Zeile ja nur ein Test ist, brauchen wir weder die normale Ausgabe >NUL noch wollen wir ggfs störende
Fehlermeldungen sehen, 2>&1 leitet die Fehlerausgabe um in die normale Ausgabe die ja schon im Scharzen Loch NUL versennkt wird.
Das nicht von dir erwähnte && führt den folgenden Befehl nur aus wenn der vorherige Findstr erfolgreich war.
Damit die Sonderzeichen diese Zeile 14 unbeschädigt passieren können habe ich beim Echo %Line% in Anführungszeichen gesetzt (und im findstr für diese zusätzlichen Zeichen einen Punkt eingfügt - wobei ich auch ein \" als escapetes Anführungszeichen hätte nehmen können)

Vielen Dank für die Top Hilfe! face-smile
Gern geschehen

Gruß
LotPings
Gruß
LotPings
Member: peter8810
peter8810 Jul 21, 2010 at 10:12:23 (UTC)
Goto Top
Hallo!

Ich hab da wieder ein Problem:

Ich habe manchmal statt
//---- Text ----//
auch
//---- Text ----
also ohne Klammer ( ) und ohne doppel Slash am Ende.

Kann ich deinen Code so gestalten, das "---- Text ----",---- Text(Text) ----", "---- Text ----" und "---- Text(Text) ----" gefunden wird?

Hab halt versucht, deinen findstr zu verändern, aber sowas wie entweder ein Leerzeichen, oder eine Klammer kann man wohl nicht suchen. Jedenfalls geht
findstr "^.//-*.*[ (].*-*[./].$" Quelle.txt  
nicht. Geht das überhaupt zwischen einem Leerzeichen und was anderem zu unterscheiden?

Grüße,
peter8810
Mitglied: 77559
77559 Jul 21, 2010 at 10:48:04 (UTC)
Goto Top
Sorry Peter,
das sind jetzt ganz andere Anforderungen (auch kaum lesbare),
die dazu notwendigen komplexen RegEx überschreiten IMO die Fähigkeiten von Findstr. (ggfs. geht es mit Gnu grep)
Außerdem wird die RegEx so unscharf das auch ungewünschte Zeilen matchen.

Gruß
LotPings
Member: peter8810
peter8810 Jul 21, 2010 at 14:01:25 (UTC)
Goto Top
Hi LotPings,

ok. Das habe ich mir nach stundenlangem probieren und lesen auch gedacht. Schade. Aber danke trotzdem face-smile

Grüße,
peter8810