Entwickler-Ecke
Algorithmen, Optimierung und Assembler - Mehrzeilige Kommentare aus einer Stringliste entfernen
immortuus - Mo 25.07.05 20:44
Titel: Mehrzeilige Kommentare aus einer Stringliste entfernen
volgender textdatei ist gegeben (lade diese in eine Stringliste):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| funktion1(1,true);
} for i := 0 to 12 do begin funktion5(1,'lala'); end; |
das ganze ist delphi syntax. ich habe aber eine eigene "scriptsprache" gebaut. ich suche nun den elegantesten weg die komentare aus der datei zu entfernen.
und bitte nicht mit irgendwelchen tolls oder regex... ich will es selber schreiben nur mit delphi boardmitteln
Moderiert von
Christian S.: Code- durch Delphi-Tags ersetzt.
maxk - Mo 25.07.05 21:34
Hallo und :welcome: im DF.
Das sollte eigentlich kein Problem sein. Du ziehst dir den gesamten Inhalt in einen String (z.B. Memo1.Lines.Text) und löscht dann alles zwischen { und } raus. Ich habe gerade kein Delphi zur Hand, aber es sollte mittels
"WHILE" und
"POS" und
"DELETE" gehen. Ich schreib nachher nochmal was, falls mir keiner zuvorkommt ;)
Gruß,
maxk
PS: Bitte benutze demnächst die Delphitags für Sourcecodeausschnitte (auch wenn es abgewandelter ist).
// Edit: Folgender Schnipsel entfernt die Kommentare, wenn die Klammern aufgehen. Falls die doppelte Zeile (7+8) kein Versehen ist, muss du allerdings daran noch ein wenig rumpfeilen.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| function RemoveComments(const Str:string):string; var p1,p2:integer; begin Result:=Str; while pos('{',Result)<pos('}',Result) do begin p1:=pos('{',Result); p2:=pos('}',Result);
Delete(Result,p1,p2-p1+1); end; end;
procedure TForm1.FormCreate(Sender: TObject); begin with Memo1.Lines do Text:=RemoveComments(Text); end; |
immortuus - Di 26.07.05 00:06
keine schlechte idee. aber leider kommt danach das raus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| funktion1(1,true); } for i := 0 to 12 do begin funktion5(1,'lala'); end; |
ich habe mir mal gedanken gemacht. ich überlege ob man dan nicht mit einer rekusiven funktion machen kann die wenn die letzte { in einem verschachtelten aufbau erschein rumdreht und beim zurückgehen alles bis } löscht. das währe dan für jeden komentar block einzeln
ps. zeile 7 und 8 sind kein versehen. darum geht es ja gerade ;-)
maxk - Di 26.07.05 00:21
Ist jetzt wahrscheinlich nicht so sauber geschrieben, aber ich schlaf schon fast ;)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| function RemoveComments(Str:string):string; var p1,p2:integer; begin Result:=''; while length(Str)>0 do begin p1:=pos('{',Str);
if p1>0 then begin Result:=Result+copy(Str,1,p1-1); Delete(Str,1,p1-1); end else begin Result:=Result+Str; Str:=''; end;
p2:=pos('}',Str); if p2>0 then Delete(Str,1,p2); end; end; |
Gruß,
maxk
sahib - Di 26.07.05 01:30
Hi.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18:
| function EntferneKommentare(s: String): String; var KlammerZaehler: Word; i : LongWord; begin KlammerZaehler := 0; for i := Length(s) downto 1 do begin if s[i] = '}' then inc(KlammerZaehler) else if s[i] = '{' then dec(KlammerZaehler);
if (KlammerZaehler > 0) or (s[i] = '{') then Delete(s, i, 1) end; Result := s end; |
*EDIT*: Result-Zeile vergessen...
Viele Grüße,
Christian
BenBE - Di 26.07.05 01:34
Das Löschen der Kommenare über einzelzeichen würde ich so nicht realisieren (jedes Zeichen einzeln aus einem Kommentar löschen), da bei jedem Löschvorgang ein komplett neuer String angelegt wird, was besonders bei langen Eingabe-Strings zu extremen Problemen führen kann.
maxk - Di 26.07.05 01:36
Verblüffent einfach :lol: Allerdings könnte ich mir vorstellen, dass das länger dauert, als mit Copy zu arbeiten, da du ja wirklich jedes Zeichen einzeln durchgehen musst. Da ich aber nur eine PE Version habe, weiss ich auch nicht wirklich, wie Copy&Delete intern arbeiten :(
Problem übrigens:
Was davon gehighlighted ist, sieht Delphi selber nichtmehr als Kommentar.
Gruß,
maxk
BenBE - Di 26.07.05 01:42
Jup. Zum einen Das, zum anderen folgender Source:
Str := '{Hallo}'; würden bisher beide Sources als Kommentar sehen und daher löschen.
Für das Kommentar-Handling von Delphi ist die erste Version richtig, für verschachtelte die zweite, für syntaktisch korrektes Entfernen der Kommentare in meinem Beispiel-Source keiner von beiden.
sahib - Di 26.07.05 01:43
Mit der Kopie des Strings stimmt natürlich. Allerdings würde ich eine solche Datei eh in einen MemoryStream laden und dort die Daten manipulieren.
Ein zu Bett gehender Christian
maxk - Di 26.07.05 01:57
So, damit sollte alles berücksichtig sein:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38:
| function RemoveComment(Str:string):string; const SD = ''''; var pS,pC:integer; begin Result:=''; while length(Str)>0 do begin pC:=pos('{',Str); if pC=0 then begin Result:=Result+Str; Str:=''; end else begin pS:=pos(SD,Str); if (pS<pC) and (pS<>0) then begin Result:=Result+copy(Str,1,pS); Delete(Str,1,pS); pS:=pos(SD,Str); if pS>0 then begin Result:=Result+copy(Str,1,pS); Delete(Str,1,pS); end else begin raise Exception.Create('Unterminated string'); end; end else begin Result:=Result+copy(Str,1,pC-1); Delete(Str,1,pC); pC:=pos('}',Str); if pC>0 then begin Delete(Str,1,pC); end else begin raise Exception.Create('Unexpected end of content in comment'); end; end; end; end; end; |
Gruß,
maxk
sahib - Di 26.07.05 13:50
So, in der Mittagspause habe ich auch noch ein wenig gefummelt ;)
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30:
| function EntferneKommentar(s: String): String; var cnt, i, j : LongWord; NichtImKommentar: Boolean; begin if s = '' then Exit; i := 1; cnt := 0; NichtImKommentar := True; while i < Length(s) do begin if NichtImKommentar then NichtImKommentar := s[i] <> #39 else if not NichtImKommentar then NichtImKommentar := s[i] = #39;
if NichtImKommentar and (s[i] = '{') then begin j := i; inc(cnt); while (j < Length(s)) and (cnt > 0) do begin inc(j); if s[j] = '{' then inc(cnt) else if s[j] = '}' then dec(cnt) end; if s[j] <> '}' then raise Exception.Create('Abschliessende Klammer fehlt.'); Delete(s, i, j - i + 1) end; inc(i) end; Result := s end; |
Ich habe gerade mal für beide Funktionen die Zeit gemessen (gleicher Datensatz: 6.2MB):
EntferneKommentar: 538 ms (der Speicherverbrauch ist auch deutlich geringer)
RemoveComment : 21860 ms
Und wenn man das dann noch über einen MemoryStream macht und nur die Pointer bewegt, dürfte das noch etwas schneller werden?
Das macht ja richtig spaß ;) Und Benny, Deine Meinung als Profi ist mir natürlich auch wichtig, wegen Stil, Anwendbarkeit etc. Du siehst das doch immer mit anderen Augen. Ich ziele immer auf Spezialfälle ab, und mache die schnell und mit wenig Speichernutzung.
Viele Grüße,
Christian
maxk - Di 26.07.05 14:30
sahib hat folgendes geschrieben: |
Ich habe gerade mal für beide Funktionen die Zeit gemessen (gleicher Datensatz: 6.2MB):
EntferneKommentar: 538 ms (der Speicherverbrauch ist auch deutlich geringer)
RemoveComment : 21860 ms |
Angeber :tongue:
Dass der Speicherverbrauch bei deiner Methode etwa halb so groß ist, ist logisch. Aber dass sie auch schneller ist, hätte ich nicht gedacht (glaub ich dir aber). Wobei mich interessieren würde, warum das so ist? Wie arbeiten pos, copy und delete den intern? Trotzdem Respekt!
Gruß,
maxk
jaenicke - Di 26.07.05 15:18
maxk hat folgendes geschrieben: |
sahib hat folgendes geschrieben: | Ich habe gerade mal für beide Funktionen die Zeit gemessen (gleicher Datensatz: 6.2MB):
EntferneKommentar: 538 ms (der Speicherverbrauch ist auch deutlich geringer)
RemoveComment : 21860 ms | Angeber :tongue:
Dass der Speicherverbrauch bei deiner Methode etwa halb so groß ist, ist logisch. Aber dass sie auch schneller ist, hätte ich nicht gedacht (glaub ich dir aber). Wobei mich interessieren würde, warum das so ist? Wie arbeiten pos, copy und delete den intern? |
Das liegt unter anderem an Pos, das geht ja auch zeichenweise durch (statt den schnelleren Boyer-Moore-Algorithmus zu benutzen).
Damit konnte ich bei einer Umsetzung in Assembler bei größeren Pattern das Pos nochmal deutlich schneller machen.
Mit BM werden die Zeichen abhängig vom gesuchten Text übersprungen, die mit dem letzten Vergleich sowieso nicht in Frage kommen. (Kann ich auch gerne noch genauer erklären :wink: )
sahib - Di 26.07.05 19:09
Hallo Sebastian.
jaenicke hat folgendes geschrieben: |
Das liegt unter anderem an Pos, das geht ja auch zeichenweise durch (statt den schnelleren Boyer-Moore-Algorithmus zu benutzen).
Damit konnte ich bei einer Umsetzung in Assembler bei größeren Pattern das Pos nochmal deutlich schneller machen. |
Boyer-Moore (BM) ist in diesem speziellen Falle allerdings völlig unangebracht. Wie Dir aufgefallen ist, hat die zu suchende Zeichenkette die Länge eins, nämlich '{'. Und da ist BM langsamer. Ohne Zweifel ist er natürlich überlegen, wenn die Suchworte länger sind.
Warum mein Code schneller ist? Zum einen habe ich nur einen Prozeduraufruf (
Delete) und zum anderen kopiere ich nichts hin und her (ok,
delete dürfte das machen). Aber selbst diese aufgerufene Prozedur könnte noch durch einen einfachen
Move-Befehl ersetzt werden können. Kurz vor der Ergebnisübergabe müsste das nur noch die neue Zeichenkettenlänge mit
SetLength neu gesetzt werden.
Christian
jaenicke - Mi 27.07.05 16:47
Ok, du hast recht, in diesem Fall bringt Boyer Moore nix, bzw. ist durch die kompliziertere Umsetzung sogar deutlich langsamer. (Wohl auch der Grund, der Borland dazu veranlasst hat, die Standard-Methode zu benutzen)
Was ich damit ausdrücken wollte war auch nur, dass die internen Routinen von Borland nicht unbedingt auf absolute Geschwindigkeit optimiert sind, bzw. das auch nicht sein können, weil sie ja das restliche Programm nicht kennen.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!