Verwendung von Quantifizierern
Nun ist es vermutlich nicht gerade praxisnah, nach Begriffen zu suchen, deren Zeichenanzahl Sie vorher schon kennen. Oder, um beim vorherigen Beispiel zu bleiben: Sie möchten schon eher nach einem
Wort suchen, dass mit »Me.« anfängt, dessen Buchstabenzahl Sie aber nicht wissen. Sie möchten also der
Such-Engine mitteilen, dass sie im Anschluss an »Me.« nach mindestens einem beliebigen weiteren Zeichen suchen soll, das unter die Kategorie »\w« fällt. Die Lösung zu diesem Problem sind die so genannten Quan-tifizierer, die Sie in der folgenden Tabelle aufgelistet finden:
{n}?Gleichbedeutend mit {n}.
| Quantifizierer | Funktion |
| * |
Setzt keine oder mehr Übereinstimmungen voraus. Beispiel: Entsprechendes Vorhandensein vorausgesetzt, findet »Me\.\w*« sowohl die Zeichenfolge »Me.« als auch »Me.Close«. Dieser Quantifizierer ist gleichbedeutend mit {0,}. |
| + |
Setzt eine oder mehr Übereinstimmungen voraus. Beispiel: »Me.\w+« findet sowohl die Zeichenfolge »Me.Close« als auch »Me.Panel1« aber nicht »Me.« oder »Mehl«. |
| ? |
Setzt keine oder eine Übereinstimmung voraus. |
| {n} |
Setzt exakt n Übereinstimmungen voraus. Beispiel: »(\w+\.){2}« findet in dem String Me.components = New System.ComponentModel.Container Me.Splitter2 = New System.Windows.Forms.Splitter die Begriffe »System.ComponentModel.« und »System.Windows.« |
| {n,} |
Setzt mindestens n Übereinstimmungen voraus. |
| {n,m} |
Setzt mindestens n, jedoch höchstens m Übereinstimmungen voraus. |
| *? |
Setzt die erste Übereinstimmung voraus, die so wenige Wiederholungen wie möglich verwendet. Dieser Befehl wird auch »faules *« (lazy *) genannt. |
| +? |
»Faules +«: Setzt so wenige Wiederholungen wie möglich voraus, jedoch mindestens eine. |
| jQuery1520781095805246027_1327273186585 |
»Faules ?«: Setzt keine Wiederholungen voraus, falls möglich, oder eine Wiederholung. |
| {n,}? |
Setzt so wenige Wiederholungen wie möglich voraus, jedoch mindestens n Wiederholungen. |
| {n,m}? |
Setzt so wenige Wiederholungen wie möglich zwischen n und m voraus. |
Sie können als Suchbegriff beispielsweise
Me\.\w+
eingeben, um zum gewünschten Ziel zu gelangen. Warum? Analysieren wir den Suchbegriff Zeichen für Zeichen. »Me« bestimmt zunächst die ersten beiden Zeichen des Präfixes der gesuchten Begriffe. Den Punkt können wir nicht im Klartext schreiben, da er selbst ein Steuerzeichen darstellt. Damit wird der vorange-stellte Backslash nötig, um die Such-Engine den Punkt als bloßes Suchzeichen betrachten zu lassen. Mit »\w« teilen wir der Engine anschließend mit, dass wir nach einem weiteren Buchstabenzeichen suchen. Das Plus schließlich erweitert die Anweisung: Die Engine sucht damit nicht nach einem Buchstabenzeichen sondern nach mindestens einem Buchstabenzeichen. Das Ergebnis lässt nicht lange auf sich warten. Klicken Sie nach Eingabe dieses Suchstrings auf die Schaltfläche Suchen, sehen Sie ein Ergebnis, etwa wie in der folgenden Abbildung zu sehen.

Verändern Sie den Suchbegriff beispielsweise in
Me\.\w*
dann zählt auch »kein Zeichen« als Kriterium für die Begriffserkennung. Das mag zunächst verwirrend sein, denn wie kann »kein Zeichen« als Kriterium gelten?
Wenn Sie alle Zeichenfolgen finden wollen, die mit »Me.« beginnen und weitere Zeichen haben, die aber auch nur aus »Me.« selbst bestehen dürfen, müssen Sie der Such-Engine mitteilen, dass nach dem Suchbe-griff Zeichen folgen dürfen, aber nicht müssen. Und das Mitteilen des »nicht müssen« entspricht dem Kriterium »kein Zeichen«.
Gruppen
Gruppen bilden Sie, wenn Sie einen großen Suchbegriff in mehrere kleine Gruppen unterteilen möchten und die Ergebnisse der kleinen Gruppen auch einzeln abrufen wollen. Sie verwenden zur Gruppenbildung runde Klammern. Dazu ein Beispiel:
Angenommen, Sie möchten den Quelltext eines Programms nach allen Prozeduren durchsuchen lassen, ganz gleich ob es sich um Properties, Subs oder Functions handelt. Sie suchen aber nach bestimmten, nämlich solchen die entweder als Private, Public oder Protected deklariert sind. Und: Sie möchten ohne große Umschweife die Ergebnisse der beiden Gruppen wissen, nämlich um welchen Gültigkeitsbereich es sich handelt und was Sie deklariert haben.
Dazu entwickeln Sie einen Suchbegriff, der die Entscheidungskriterien für den Gültigkeitsbereich in der ersten Gruppe
(Private|Public|Protected)
ein Trennzeichen dazwischen und die Prozedurart mit
(Sub|Property|Function)
in der zweiten Gruppe enthält. Fügen Sie diese einzelnen Komponenten zu einem Gesamtsuchbegriff zu-sammen, etwa mit
(Private|Public|Protected)\s(Sub|Property|Function)
dann erhalten Sie, angewendet auf den Beispiel-Quellcode, ein Ergebnis, etwa wie in folgender Abbildung zu sehen.

Das Tolle daran: Sie haben mit Gruppen Zugriff auf – in diesem Beispiel – alle drei Gruppen. Drei? Genau. Mit einer (der ersten) Gruppe arbeiten Sie grundsätzlich – denn sobald Sie einen Suchbegriff eingeben, erstellen Sie bereits die erste Gruppe. Das gesamte Suchergebnis entspricht deswegen auch immer dem Ergebnis der 1. Gruppe. In diesem Beispiel haben wir explizit zwei weitere Gruppen definiert – die entspre-chenden Ergebnisse spiegeln sich in Gruppe 2 und 3 wider, was Sie in der Abbildung auch sehr schön erkennen können.
Gruppen eignen sich nicht nur dazu, beim Programmieren mit Regulären Ausdrücken elegant auf Teil-ergebnisse zugreifen zu können. Insbesondere beim Ersetzen von Begriffen leisten sie hervorragende Dienste. Durch Gruppen, die Sie im Übrigen auch benennen können, lassen sich Ersetzungen individuali-sieren. Dazu benötigen Sie allerdings weitere Informationen über Steuerzeichen, die Sie im Ersetzen-Ausdruck für Reguläre Ausdrücke verwenden können.
Suchen und Ersetzen
Diese speziellen Steuerzeichen können Sie ausschließlich beim Ersetzen einsetzen. Die nachstehende Tabelle zeigt, welche Steuerzeichen die Regular-Expression-Engine für das Ersetzen von Ausdrücken versteht:
| Zeichen | Beschreibung |
| $number |
Ersetzt die letzte untergeordnete Zeichenfolge, die der Gruppennummer number (dezimal) entspricht. |
| ${name} |
Ersetzt die letzte untergeordnete Zeichenfolge, die einer (?)-Gruppe entspricht. |
| $$ |
Ersetzt ein einzelnes "$"-Literal. |
| $& |
Ersetzt eine Kopie der gesamten Entsprechung. |
| $` |
Ersetzt den gesamten Text der Eingabezeichenfolge vor der Entsprechung. |
| $' |
Ersetzt den gesamten Text der Eingabezeichenfolge nach der Entsprechung. |
| $+ |
Ersetzt die zuletzt erfasste Gruppe. |
| $_ |
Ersetzt die gesamte Eingabezeichenfolge. |
Um beim vorhandenen Beispiel zu bleiben: Wenn Sie alle Prozeduren, ganz gleich, wie Sie sie zuvor definiert haben, durch den Gültigkeitsbereichsbezeichner Private ersetzen wollen, verwenden Sie als Suchbegriff den bereits bekannten
(Private|Public|Protected)\s(Sub|Property|Function)
und als Ersetzungsbegriff folgenden:
Private $2
Mit »$2« greifen Sie auf das Ergebnis der zweiten Gruppe zu – in diesem Beispiel die Prozedurenart, denn sie ist an zweiter Stelle definiert worden. Das Ergebnis der ersten Gruppe interessiert Sie nicht, denn Sie ersetzen es ohnehin durch die Zeichenfolge »Private«.
Das gleiche Beispiel mit benannten Gruppen sähe folgendermaßen aus:
(?<GBereich>Private|Public|Protected)\s(?<Prozedur>Sub|Property|Function)
würden Sie hierbei als Suchstring und
Private ${Prozedur}
als Ersetzungszeichenfolge verwenden.
Nun könnten wir dieses Beispiel noch weiter spinnen und eine Ersetzungsroutine entwickeln, die den vor-mals vorhandenen Gültigkeitsbereich als Kommentar hinter die Definition setzt. Dazu müssen wir den Suchbegriff um eine weitere Gruppe erweitern, die den Rest der Zeile als insgesamt zu findende Zeichenfol-ge mit einschließt, etwa folgendermaßen:
Die Suchzeichenfolge:
(?<GBereich> Public|Protected)\s(?<Prozedur>Sub|Property|Function)(?<Rest>[^\r^\n]*)
Die Ersetzenzeichenfolge:
Private ${Prozedur}${Rest} ' Vormals: ${GBereich}
Und das Ergebnis sehen Sie in folgender Abbildung:

Captures
Captures sind dann interessant, wenn Quantifizierer bei Gruppenoperationen ins Spiel kommen. Um auch hier wieder beim Beispiel zu bleiben: Sie möchten wissen, aus welchen Variablen – so vorhanden – die einzelnen Prozedurenaufrufe bestehen. In diesem Fall legen Sie eine Regel an, die die einzelnen Variablen erfassen kann – und zwar so, dass ein Quantifizierer auf den gesamten Ausdruck anwendbar wird. Zum Beispiel:
\((([\w|\x20|\.])+[\,|\)])+
Schauen wir uns den Ausdruck einmal genauer an. Erste Regel: (»\(«) – er muss mit einer Klammer begin-nen. Dann beginnt der eigentliche zu wiederholende Ausdruck:
(([\w|\x20|\.])+[\,|\)])+
Dieser besteht wiederum aus zwei Ausdrücken, nämlich
([\w|\x20|\.])+
und
[\,|\)]
Ausdruck Nummer eins legt alle nach der Klammer vorkommenden Zeichen so fest, dass sie aus Buchsta-ben, Leerzeichen oder dem Punkt bestehen dürfen. Das anschließende Quantifizierungszeichen »+« defi-niert, dass diese Zeichen sich beliebig wiederholen dürfen, aber mindestens einmal vorhanden sein müssen.
Der zweite Ausdruck regelt das Ende eines Parameterblocks, der mit einem Komma oder einer schließenden Klammer enden kann. Beide Ausdrücke zusammengefügt ergeben die komplette Parameterregel innerhalb der Klammer. Und jetzt kommt der Trick: Da wir nicht wissen, wie viele Parameter innerhalb eines Proze-durenprototypen definiert sind, setzen wir den »+«-Quantifizierer ans Ende, und schon kann uns egal sein, wie viele Parameter folgen – der Quantifizierer sorgt dafür, dass entsprechend viele gefunden werden.
Anschließend schnappen wir uns den Suchstring aus dem vorherigen Beispiel und modifizieren ihn so, dass eine weitere Gruppe für den Funktionsnamen gefunden werden kann. Das ist vergleichsweise einfach: Lediglich der Ausdruck
\s(\w+)
muss noch eingefügt werden. Das »\s« regelt die Trennung zwischen Prozedurentypnamen und Funktions-namen; die Gruppe »(\w+)« deckt den Funktionsnamen ab. Packen wir alles zusammen, erhalten wir fol-genden Gesamtsuchstring:
(?<GBereich>Private|Public|Protected)\s(?<Prozedur>Sub|Property|Function)\s(\w+)\((([\w|\x20|\.])+[\,|\)])+
Eindrucksvoll, oder nicht? Ganz ehrlich: So einfach, wie ich diese Beschreibung hier herunter geschrieben habe, war das Austüfteln dieses Strings nicht – es hat mich immerhin drei Stunden gekostet. Nichtsdestotrotz hat sich der Aufwand gelohnt, denn: Spätestens an dieser Stelle werden Sie den Nutzen der Captures kennen lernen.
Um die Captures der einzelnen Gruppen auch sichtbar zu machen, wählen Sie aus dem Menü Datei die Option GroupCaptures anzeigen.
Wenn Sie diesen String auf die zuvor geladene Visual Basic-Datei anwenden (keine Angst, Sie können diese Mammutkonstruktion aus der Bibliothek holen), können Sie sich die Captures der einzelnen Gruppen ebenfalls in der Ergebnisliste betrachten – etwa wie in unten stehender Abbildung zu sehen.
Da wir die Parameterfindung so allgemeingültig gehalten haben, dass wir einen Quantifizierer einsetzen konnten, kommen wir über die Captures an jede einzelne Zeichenfolge, die durch die Quantifizierer in Kombination mit dem eigentlichen Gruppensuchstring gefunden wurde. Und das sind bei der 3. Gruppe eben die einzelnen Parameter.
Sie sehen, dass wir nur durch die Anwendung von Regulären Ausdrücken schon auf dem besten Wege sind, einen kompletten Cross-Referenzer zu kreieren – und bislang haben wir noch nicht eine einzige Zeile Code dafür schreiben müssen!

8885f667-1143-4698-a666-6bf0c698f56a|1|5.0
Tags: |
Categories: RegEx