Entwickler-Ecke

Sonstiges (Delphi) - Problem mit Regulären Ausdruck - TRegExpr


Ares - Mo 15.03.10 15:57
Titel: Problem mit Regulären Ausdruck - TRegExpr
Hallo!

Ich verwende die Klasse TRegExpr von Andrey Sorokin um in Delphi Reguläre Ausdrücke nutzen zu können. Nun will ich Textdatei parsen die ähnlich einer normalen INI-Datei aufgebaut ist (nur das Format der Werte unterscheidet sich):


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
[Section1]
Werte...
Werte...
Werte...

[Section2]
Werte...
Werte...
Werte...


Beim Parsen der Datei will ich nun zunächst die einzelnen Sections herausfiltern und hierfür einen regulären Ausdruck verwenden. Bislang habe ich einen Ausdruck verwendet, der neben dem Section-Header auch direkt die einzelnen Werte zerlegt. Dieser war aber scheinbar zu komplex, denn bei der Anwendung auf sehr lange Werte kommt es beim Matching zu einem Stacküberlauf.

Ich suche daher nach einem einfachen Ausdruck, der mir eine Section mit den zugehörigen Werten zurück liefert. Umgangssprachlich wäre das einfach "Alles vom Sektion-Header bis zur nächsten Zeile in der erste Zeichen ein [ ist".

Das Problem ist, dass ich nicht weiß wie man "Suche alles was NICHT \r\n[ ist".

Eine bestimmte Zeichenkette zu suchen ist ja kein Problem, aber alles zu suchen was NICHT einer bestimmten Zeichenkette entspricht bekomme ich nicht hin.

Wie gebe ich also eine Zeichenkette als Suchmuster an und negiere diese? Geht das überhaupt?

Ich könnte natürlich einfach so vorgehen: "Suche Section-Header, dann beliebigen Inhalt bis nach einem Zeilenumbruch [ gefunden wird]". Hierbei ist aber das Problem, dass dann der Zeilenumbruch und die eckige Klammer zum ersten Match gehören. Starte ich dann die Suche nach dem nächsten Match sähe der Rest nur noch so aus: "Section2]...".

Das Ziel ist also:
Finde alle Inhalte bis zum Beginn einer neuen Section. Nimm hierbei aber nicht den Beginn der nächsten Section in den Match mit auf.


Ist das überhaupt möglich?

Besten Dank
Ares


Wolle92 - Mo 15.03.10 17:13

du musst ja nicht gleich den kompletten match aus dem string rauspflücken...

ich kenne die TRegExpr-Klasse nicht, aber in PHP würd ich das ganze so machen:

Quelltext
1:
preg_match_all('~(\[\w+\].*)\r\n\[~',$ini_content,$matches,PREG_SET_ORDER);                    

dann hätte ich in matches ein mehrdimensionales Array, für jede Section ein Eintrag. In $matches[0][0] hätte ich den kompletten Match, in $matches[0][1] nur die Klammer.

Sowas sollte es doch in der TRegExpr auch geben, oder?
dann hätte ich noch nen besseren RegEx:

Quelltext
1:
~\[(\w+)\](.*)\r\n\[~                    

So würde ich das gleiche Muster suchen, hätte in den Match-Ergebnissen aber direkt Section-Name und die einzelnen Werte getrennt.

Wenn das so nicht funktioniert, nimmst du den ersten RegEx und entfernst nach der suche einfach nur das, was in der Klammer steht, aus dem ursprünglichen String.

Grüße,
Wolle

Edit: Ich weiß nicht, inwieweit das in Delphi implementiert ist, aber ansonsten wären lookarounds noch ne lösung:

Quelltext
1:
~(?:\[(\w+)\](.*)\r\n)(?=\[)~                    

Man korrigiere mich, sollte mir ein Fehler unterlaufen sein, RegExp sind nicht grade die einfachste Materie :P

Edit#2: Das Problem allgemein ist doch, das die letzte Section gar nicht mehr gematcht wird?
würde das gelöst durch:

Quelltext
1:
~(?:\[(\w+)\](.*)\r\n)(?=[\[$])~                    

Man beachte den Lookahead (?=[\[$]) um sowohl ne neue eckige Klammer als auch das Ende des Strings zu matchen.


Narses - Mo 15.03.10 18:03

Moin!

user profile iconAres hat folgendes geschrieben Zum zitierten Posting springen:
Ich verwende die Klasse TRegExpr von Andrey Sorokin um in Delphi Reguläre Ausdrücke nutzen zu können. Nun will ich Textdatei parsen die ähnlich einer normalen INI-Datei aufgebaut ist (nur das Format der Werte unterscheidet sich):
[...]
Beim Parsen der Datei will ich nun zunächst die einzelnen Sections herausfiltern und hierfür einen regulären Ausdruck verwenden.
Das Verarbeiten von regulären ausdrücken ist sehr aufwändig und deshalb unglaublich langsam, gerade wenn man große Mengen Quelldaten verarbeitet. :idea:

Bei so einer einfachen Aufgabe würde ich das nicht mit TRegExpr machen, das geht mit einer Stringliste und ein paar Zeilen Code sehr viel einfacher und vor allem schneller/resourcenschonender! :nixweiss:

cu
Narses


Wolle92 - Mo 15.03.10 22:31

Aber dafür haben reguläre Ausdrücke ein viel tolleres Aussehen! :P