Home » Tutorials » Object Pascal/RTL » Reguläre Ausdrücke in Delphi

Reguläre Ausdrücke in Delphi

Matcher und Gruppen

Matcher

Bei einem Match handelt es sich um eine gefundene Stelle in einem Eingabetext, auf die der reguläre Ausdruck passt. Es können auch mehrere Treffer vorkommen. Wenn es darum geht, passende Stellen zu finden, bietet Delphi am Typ TRegEx einige Funktionen an.
Für die folgenden Beispiele nehmen wir einen etwas längeren Text und einen einfachen regulären Ausdruck, der nach „Delphi“ sucht. Bei letzterem verzichten wir auf ^ und $, weil das Wort überall im Text vorkommen darf.

var input, regex: String;
...
input := 'Delphi ist ein tolles Werkzeug, um Desktop-Anwendungen zu entwickeln. ' +
'Ich nutze Delphi XE3 schon längere Zeit.';
regex := 'Delphi';

IsMatch

Die Funktion IsMatch haben wir bereits im vorigen Beispiel gesehen. Sie prüft, ob der reguläre Ausdruck mindestens einmal auf den Eingabetext anwendbar ist, und gibt dann true zurück. Ansonsten false. Wir erfahren aber nichts über Anzahl der Treffer oder deren Position.

ShowMessage(BoolToStr(TRegEx.IsMatch(input, regex), true));

Dieser Code gibt „True“ aus, weil das Wort „Delphi“ (mit beliebig vielen Zeichen davor und danach) im Input-Text vorkommt. Würde „Delphi“ nicht vorkommen, wäre der Rückgabewert logischerweise false.

Match

Die Methode Match gibt keinen Boolean-Wert zurück, sondern ein Objekt vom Typ TMatch. Dabei handelt es sich um einen Record, der Detail-Information zum ersten Treffer beinhaltet:

var match: TMatch;
begin
  match := TRegEx.Match(input, regex);

Wurde ein Treffer gefunden, enthält das Match-Objekt folgende Daten:

  • Value enthält den Text, der auf den regulären Ausdruck matcht. Bei uns ist das das Wort „Delphi“. Da wir genau danach gesucht haben, ist das wenig überraschend. Wenn wir aber nach einem Ausdruck wie D[w]{4}i gesucht hätten, wären auch andere Textteile in Frage gekommen.
  • Index enthält die Position im Orginal-String, an der der Treffer gefunden wurde (Zählung beginnt bei 0). In unserem Beispiel ist der Wert 0, weil „Delphi“ direkt das erste Wort ist.
  • Length enthält die länge des Treffer-Textes. In unserem Beispiel 6.
  • NextMatch gibt ein Match-Objekt für den nächsten Treffer zurück.

Wurde kein Treffer gefunden, erhält man nicht nil, sondern auch ein Objekt vom Typ TMatch. Über die Eigenschaft „Success“ lässt sich prüfen, ob es sich um einen Treffer handelt. Das gilt sowohl beim ersten Aufruf von Match als auch beim Aufruf von NextMatch.

Die dritte Methode zum Auffinden von Treffern ist „Matches“. Diese gibt nicht wie „Match“ einen einzelnen Treffer zurück, sondern direkt alle in Form einer TMatchCollection (ebenfalls ein Record). Diese enthält pro Treffer ein TMatch-Objekt. Über die Property „Count“ lässt sich direkt die Anzahl der Treffer feststellen.

var
  matches: TMatchCollection;
...
matches := TRegEx.Matches(edInput.Text, edRegex.Text);

Auf folgende Weise kann man über alle Treffer iterieren (sofern vorhanden) und sich deren Position im Text anzeigen lassen:

var
  matches: TMatchCollection;
  match: TMatch;
begin
  matches := TRegEx.Matches(input, regex);
  if matches.Count > 0 then
  begin
    for match in matches do
    begin
      ShowMessage('Treffer an Position ' + IntToStr(match.Index));
    end;
  end;
end;

Bei der Verwendung der Methode Matches sollte man an den einzelnen TMatch-Objekten nicht NextMatch aufrufen, sondern über die Ergebnismenge iterieren, wie z.B. in obigem Beispiel.

Gruppen

In regulären Ausdrücken kann man mit Hilfe von runden Klammern Teile eines Treffers besonders markieren. Diese Gruppen lassen sich anschließend gesondert abrufen.
Beispiel: Wir suchen in einem Text nach Delphi-Versionsnummern. Damit die Treffer auch korrekt sind, muss der gefundene Text mit „Delphi“ beginnen. Nach einem Leerzeichen soll dann die Versionsnummer kommen. Damit nicht jedes beliebige Wort gefunden wird, geben wir ein paar Versionen vor. Bei der Auswertung interessiert uns aber nur die Versionsnummer – ohne „Delphi“ davor. Deshalb umgeben wir die Versionsnummer mit runden Klammern.
Wir nehmen also weiterhin die in obigem Beispiel definierte Input-Variable und folgenden neuen regulären Ausdruck:

regex := 'Delphi (XE2|XE3|XE)';

Wie bereits erwähnt suchen wir damit also „Delphi“ gefolgt von einem Leerzeichen und der Versionsnummer XE2, XE3 oder XE. „XE“ steht dabei als letzte Variante, weil „XE2“ und „XE3“ ja auch auf „XE“ matchen würden. Zu beachten sind die runden Klammern und die Versionsangabe. Diese stellen eine Gruppe (oder einen Teilausdruck) dar. In einem Pattern können auch durchaus mehrere Gruppen vorkommen. In unserem Fall ist es nur eine.
Wie greifen wir nun auf diese Gruppen zu? Zunächst einmal benötigen wir wieder einen Treffer im Text, also ein TMatch-Objekt wie oben beschrieben. Dieses TMatch-Objekt können wir nun nach seinen Gruppen fragen:

var
  match: TMatch;
  groups: TGroupCollection;
  group: TGroup;
begin
  match := TRegEx.Match(input, regex);
  groups := match.Groups;
  for group in groups do
  begin
    if (group.Success) then
      ShowMessage('Wert: ' + group.Value);
  end;
end;

Über den Aufruf von „Group“ erhalten wir also eine TGroupCollection, die aus TGroup-Objekten besteht. Diese sind analog zu TMatch aufgebaut und enthalten Success, Value, Index und Length.
In obigem Beispiel iterieren wir über alle Gruppen eines Treffers. Dabei wird als erstes die Gruppe 0 ausgegeben. Bei dieser handelt es sich um den komplettem Match (bei uns „Delphi XE3“). Erst bei Gruppe 1 kommt der Teil in den runden Klammern zur Ausgabe: „XE3“.