Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.
Reguläre Ausdrücke dienen mitunter nicht nur der Mustererkennung, sondern leisten hervorragende Dienste beim Ersetzen bestimmter Zeichenfolgen. Damit Sie unter VBA von regulären Ausdrücken profitieren können, lernen Sie in diesem Beitrag die grundlegenden Techniken kennen und erfahren, wie Sie beinahe beliebige Ausdrücke in Zeichenketten erkennen und ersetzen können. Schließlich liefert der Betrag ein Beispiel zum Erkennen der VBA-Schlüsselwörter in Codemodulen.
Reguläre Ausdrücke (Regular Expressions, kurz RegExp) dienen zum Suchen und Ersetzen von Textelementen.
Reguläre Ausdrücke sind kein Bestandteil von VBA, sondern müssen über das Setzen eines Verweises auf die Bibliothek Microsoft VBScript Regular Expressions 5.5 verfügbar gemacht werden.
Im Code erzeugen Sie dann eine Instanz des Objekts RegExp und speichern den Verweis darauf in einer entsprechenden Objektvariablen:
Dim objRegExp As RegExp Set objRegExp = New RegExp
Das RegExp-Objekt hat einige wenige Eigenschaften, die folgende Aufgabe haben:
- IgnoreCase: Legt fest, ob Groß-/Kleinschreibung beachtet werden soll.
- Global: Sollen nur das erste (Standard, False) oder alle Fundstellen (True) zurückgegeben werden
- Pattern: Legt das Muster fest, nach dem gesucht werden soll.
- Multiline: Gibt an, ob durch Zeilenumbrüche getrennte Teile einer Zeichenkette als neuer Ausdruck untersucht werden sollen. Dies erlaubt beispielsweise das Verwenden des Zeilenbeginn- und Zeilenende-Zeichens in Ausdrücken.
Aktionen
Prinzipiell können Sie mit RegExp suchen oder suchen und ersetzen. Wenn Sie einfach nur prüfen möchten, ob ein Ausdruck in einem anderen Ausdruck vorkommt, geben Sie das Pattern an und prüfen den zu durchsuchenden Ausdruck mit der Test-Funktion. Diese liefert True oder False zurück.
Wenn Sie den gefundenen Ausdruck gleich ersetzen möchten, verwenden Sie statt Test die Replace-Methode. Diese erwartet entsprechend gleich zwei Parameter, nämlich den zu durchsuchenden String sowie die Zeichenkette, die statt des in Pattern angegebenen Ausdrucks verwendet werden soll.
Einfache Suche
Die einfachste Suche realisieren die folgenden Codezeilen. Die Funktion prüft schlicht, ob sich der mit strSuchbegriff übergebene Ausdruck in strOriginal befindet und gibt entweder True oder False zurück:
Public Function EinfacheSuche( _ strOriginal As String, _ strSuchbegriff As String) As Boolean Dim objRegExp As RegExp Set objRegExp = New RegExp With objRegExp .Pattern = strSuchbegriff EinfacheSuche = .Test(strOriginal) End With Set objRegExp = Nothing End Function
Der folgende Ausdruck würde im Direktfenster also beispielsweise den Wert True zurückliefern:
EinfacheSuche("cd", "abcdef")
Einfaches Suchen und Ersetzen
Die einfachste Suchen- und Ersetzen-Funktion bildet (fast) die Replace-Funktion von VBA ab. Sie erwartet die gleichen Parameter, also den Originalausdruck, den zu ersetzenden Ausdruck und den Ersatzausdruck.
Der Unterschied ist jedoch, dass hier nur das erste Auftreten des gesuchten Begriffs ersetzt wird. Der Grundaufbau ist wie beim reinen Suchen, allerdings kommt hier nicht die Test-Funktion, sondern die Replace-Funktion zum Einsatz.
Diese erwartet zusätzlich den Ersatzbegriff als Parameter und liefert auch keinen Boolean-Wert zurück, sondern gleich die geänderte Zeichenkette:
Public Function SuchenUndErsetzen( _ strOriginal As String, _ strSuchbegriff As String, _ strErsatzbegriff As String) As String Dim objRegExp As RegExp Set objRegExp = New RegExp With objRegExp .Pattern = strSuchbegriff SuchenUndErsetzen = _ .Replace(strOriginal, strErsatzbegriff) End With Set objRegExp = Nothing End Function
Ein einfacher Aufruf sieht wie folgt aus und liefert das entsprechende Ergebnis zurück:
EinfachesSuchenUndErsetzen("abcdef", "cd", "xx") abxxef
Es kann auch sein, dass der Suchbegriff gleich mehrfach im Originalausdruck vorkommt. Um die Replace-Funktion von VBA vollwertig abzubilden, müssen wir den Suchbegriff an allen vorkommenden Stellen ersetzen. Dazu brauchen Sie einfach noch die Eigenschaft Global von objRegExp auf True einzustellen.
Alle Fundstellen einzeln betrachten
Gegebenenfalls sollen nicht alle Suchergebnisse über einen Kamm geschert werden, sondern Sie möchten diese einzeln behandeln.
Dann sind das MatchCollection– und das Match-Objekt interessant. Sie müssen für beide eine Objektvariable deklarieren:
Dim objMatchCollection As MatchCollection Dim objMatch As Match
Danach übergeben Sie das Ergebnis der Execute-Methode im MatchCollection-Objekt und durchlaufen alle darin enthaltenen Match-Objekte und geben einige Information pro Fundstelle aus:
Set objRegExp = New RegExp With objRegExp .Pattern = strSuchbegriff .Global = True Set objMatchCollection = _ .Execute(strOriginal) For Each objMatch In objMatchCollection Debug.Print "Position: " _ & objMatch.FirstIndex, "Wert: " _ & objMatch.Value, "Länge: " _ & objMatch.Length Next objMatch End With
Ein Beispielaufruf sieht etwa so aus:
SuchergebnisseEinzelnBearbeiten "abcdefcd", "cd" Position: 2 Wert: cd Länge: 2 Position: 6 Wert: cd Länge: 2
Das Match-Objekt liefert nützliche Informationen. Im obigen Beispiel geben wir die folgenden drei je Fundstelle aus:
- FirstIndex: Position, an welcher der Suchbegriff befindet. Achtung: 0-basiert!
- Value: Wert des gefundenen Ausdrucks. Im einfachen Beispiel von oben entspricht dieser natürlich immer dem Suchausdruck. Aber da dieser auch mit Platzhaltern angegeben werden kann, kann durchaus jeder Treffer anders aussehen.
- Length: Hier gilt das Gleiche wie für den Treffer selbst: Seine Länge kann ja nach Formulierung des Suchbegriffs durchaus variieren. Beispiele folgen!
Ausdrücke zusammenstellen
Nachdem Sie wichtige Grundtechniken für den Einsatz regulärer Ausdrücke kennengelernt haben, schauen wir uns nun die Ausdrücke beziehungsweise die sogenannten Pattern selbst an.
Die einfachste Möglichkeit ist natürlich die Angabe einer konkreten Zeichenkette. Sicher kennen Sie das Sternchen und das Fragezeichen als Platzhalter für beliebig viele beziehungsweise ein einziges Zeichen in Access-SQL-Bedingungen.
Reguläre Ausdrücke bieten hier wesentlich aufgefeiltere Möglichkeiten:
- Punkt (.): Beliebiges Zeichen außer Zeilenumbruch. a. findet also etwa ab, ac oder a1.
- Sternchen (*): Keine, eine oder mehrere Wiederholungen des vorhergehenden Zeichens. abc* würde also beispielsweise ab, abc, abcc oder abccc finden.
- Fragezeichen (): Kein oder ein Vorkommen des vorhergehenden Zeichens. abc findet also etwa ab oder abc.
- Pluszeichen (+): Ein oder mehrere Vorkommen des vorhergehenden Zeichens. abc+ findet also etwa abc, abcc oder abccc.
- Geschweifte Klammern ({}): In den Klammern können ein oder zwei durch Komma getrennte Zahlen stehen, die eine Information über die Anzahl des Vorkommens des vorhergehenden Zeichens enthalten. Eine einzige Zahl gibt die genaue Anzahl an, a{3} ist somit Platzhalter für aaa. Zwei durch Komma getrennte Zahlen geben kleinste und größte Anzahl des vorherigen Zeichens an, a{1,3} ist also Platzhalter für a, aa und aaa. Fehlt die Zahl vor dem Komma, wird dort der Wert 0 angenommen. ab{,2} ist also Platzhalter für a, ab und abb. Fehlt die Zahl nach dem Komma, kann die maximale Anzahl beliebig groß sein. ab{1,} steht also für ab, abb, abbb und so weiter.
- Eckige Klammern ([]) definieren Zeichenklassen. [abc] repräsentiert eines der Zeichen a, b oder c. [a-z] entspricht allen Buchstaben von a bis z.
- Eckige Klammern können auch auszuschließende Zeichen angeben. Dazu enthält die Klammer als erstes das Caret-Zeichen (^). [^abc] entspricht allen Zeichen außer a, b und c.
- Eckige Klammern können auch nicht zusammenhängende Zeichen oder Bereiche enthalten. [abd-f] ist beispielsweise Platzhalter für die Buchstaben a, b, d, e und f.
- Spezielle Platzhalter sind \d (alle Zahlen), \D (keine Zahl), \w (Buchstabe, Zahl oder Unterstrich), \W (alles außer Buchstaben, Zahlen oder Unterstrich), \s (Leerzeichen, Tabulator, Zeilenumbruch) oder \S (alles außer Leerzeichen, Tabulator, Zeilenumbruch).
- Alternativen werden in Klammern und durch das Pipe-Zeichen (|) getrennt angegeben. (abc|efg) steht so für eine der Zeichenfolgen abc oder efg.
- Caret-Zeichen (^): Steht für den Zeilen- beziehungsweise Zeichenkettenbeginn. ^Sub liefert also alle Fundstellen, bei den Sub am Zeilenanfang steht. Das Caret-Zeichen steht normalerweise nur stellvertretend für den Beginn der kompletten Zeichenkette, unabhängig davon, ob diese noch Zeilenumbrüche enthält. Wenn eine neue Zeile ebenfalls mit dem Caret-Zeichen erkannt werden soll, müssen Sie zuvor die Eigenschaft Multiline auf True einstellen.
- Dollar-Zeichen ($): Steht für das Zeilen- beziehungsweise Zeichenkettenende. Sub$ liefert also solche Fundstellen, bei denen Sub am Ende steht. Gut, um beispielsweise Prozedurenden zu finden. Bezüglich Zeilenumbrüche gilt hier das Gleiche wie beim Caret-Zeichen: Sie müssen die Eigenschaft Multiline auf True einstellen, damit jedes Zeilenende und nicht nur das Ende des kompletten Ausdrucks über das Dollar-Zeichen erkannt werden soll.
- Backslash (\): Möglicherweise möchten Sie in Texten auch nach Sonderzeichen suchen, die eine spezielle Funktion in regulären Ausdrücken haben. In diesem Fall stellen Sie dem Zeichen einen Backslash voran. Mit abc\$ suchen Sie also dann schlicht nach der Zeichenkette abc$ und nicht etwa nach einem Vorkommen von abc am Zeilenende oder am Ende der Zeichenkette.
- Wagenrücklauf (\r): entspricht vbCr
- Zeilenvorschub (\n): entspricht vbLf
- Wagenrücklauf und Zeilenvorschub (\r\n): entspricht vbCrLf
- Tabulator (\t): entspricht vbTab
Suchen und ersetzen
Mit der Kenntnis der möglichen Ausdrücke und ein wenig Übung werden Sie schnell die gewünschten Zeichenketten finden. Es gibt jedoch noch einen sehr wichtigen Tipp für das Ersetzen von Zeichenketten.
Bei der Replace-Funktion von VBA tauschen Sie einfach einen Teilausdruck gegen einen anderen aus, wobei ersterer dem Suchbegriff entspricht. Wenn Sie dort nun beispielsweise den Ausdruck cde nicht überall durch xyz möchten, sondern nur dort, wo der Ausdruck in einem bestimmten Kontext steht (also beispielsweise dort, wo er in bestimmte andere Zeichenfolgen eingefasst ist – beispielsweise abcdefg), müssen Sie erst nach abcdefg suchen und dann mühsam mit weiteren Zeichenkettenfunktionen den darin enthaltenen Ausdruck ersetzen.
ab und fg stehen hier stellvertretend für variable Ausdrücke – sonst könnten Sie ja auch einfach abcdefg durch abxyzfg ersetzen!
Reguläre Ausdrücke bieten hier eine tolle Variante: Sie können dort einfach den Bereich, der nicht ausgetauscht werden soll, in Klammern einfassen und diesen nachher in den neuen Ausdruck integrieren. Sie suchen also nach folgendem Ausdruck:
(ab)cde(fg)
Nun soll der mittlere Teil (cde) überall durch xyz ersetzt, die umschließenden Teile aber beibehalten werden. Dann geben Sie als neuen Ausdruck einfach den folgenden an:
$1xyz$2
$1 wird in diesem Fall durch den ersten in Klammern eingefassten Ausdruck ersetzt, $2 durch den zweiten. Auf diese Weise können Sie beliebig viele Elemente des Suchausdrucks in den Ersatzausdruck hinüberretten.
Vertauschen
Mit dieser Technik können Sie natürlich auch einfach Ausdrücke vertauschen. Wenn Sie beispielsweise das Datumsformat in einem Text von DD.MM.YYYY in YYYY/MM/DD ändern möchten, lautet der Suchausdruck wie folgt:
(\d{1,2})\.(\d{1,2}).(\d{4})
Der neue Ausdruck sieht so aus:
$3/$2/$1
Das bedeutet: Ein Auftreten von ein oder zwei Zahlen, einem Punkt, weiteren ein oder zwei Zahlen, einem weiteren Punkt und vier Zahlen soll ersetzt werden durch die vier Zahlen, einen Schrägstrich, die mittleren ein oder zwei Zahlen, einen weiteren Schrägstrich und die vorderen zwei Zahlen.
Beispiel Pfad-/Dateiname
Wenn Sie aus einem Dateinamen mit Pfad nur den Pfad erhalten möchten, geht das zwar auch mit den Zeichenkettenfunktionen von VBA recht einfach. Aber es ist ein gutes Beispiel für eine erste Übung.
Wie lautet die Anforderung, wenn wir aus c:\test\test.txt den Teil c:\test\ erhalten möchten Genau: Liefere alles, was mit einem Backslash endet. Der entsprechende Ausdruck sieht so aus:
.*\\
Der Ausdruck liefert beliebig viele Zeichen, wobei das letzte ein Backslash sein muss. Warum liefert RegExp nicht nur c:\
Weil es gierig ist: Es ermittelt erst die Zeichenfolge aus beliebig vielen Zeichen (.*) und geht dann von hinten nach vorne zum ersten Backslash zurück.
Um nun nur den Dateinamen, also test.txt zu erhalten, probieren wir es andersherum:
\\.*
Dies gelingt jedoch nicht: RegExp sucht erst einen Backslash und hängt dann die folgenden Zeichen an. Das Ergebnis sieht so aus:
\test\test.txt
Die richtige Lösung lautet:
[^\\]*$
Das Dollar-Zeichen sorgt dafür, dass der Ausdruck das Ende der Zeichenkette einschließt, und der vordere Teil liefert beliebig viele aufeinanderfolgende Zeichen, die kein Backslash sind.
Komplexes Beispiel: Schlüsselwörter in VBA-Code markieren
Im Beitrag Berichte ohne Datenherkunft (www.access-im-unternehmen.de/****) sollen in einem Beispiel Schlüsselwörter in VBA-Code farbig ausgegeben werden.
Die Vorarbeit dazu soll mit Hilfe regulärer Ausdrücke erledigt werden, und zwar durch Hervorheben der gesuchten Schlüsselwörter durch Voranstellen einer speziellen Zeichenkombination (hier \@).
Für einen ersten Versuch wollen wir die folgende typische Zeile anpassen:
Public Sub Test()
Diese soll nach dem Bearbeiten so aussehen:
\@Public \@Sub Test()
Die notwendige Funktion sieht wie folgt aus, wobei diese zunächst einen Suchausdruck enthält, der nur aus wenigen Schlüsselwörtern besteht:
Public Function SchluesselwoerterErsetzen(_ strModul As String) As String Dim objRegExp As RegExp Dim strSchluesselwoerter As String Set objRegExp = New RegExp strSchluesselwoerter = "((Public|Private |Friend|Sub|Function|Property|Get| Set|Let|As|Optional))" With objRegExp .Pattern = strSchluesselwoerter .Global = True SchluesselwoerterErsetzen = _ .Replace(strModul, "\@$1") End With Set objRegExp = Nothing End Function
Der Aufruf erfolgt beispielsweise so und liefert gleich ein entsprechendes Ergebnis:
SchluesselwoerterErsetzen("Public Sub Test()") \@Public \@Sub Test()
Der erste Ansatz für den Suchausdruck soll zunächst nur die erste Zeile einer Prozedur durchforsten und enthält daher nur die dort verwendeten Begriffe (die Datentypen fehlen noch):
((Public|Private|Friend|Sub|Function|Property|Get|Set|Let|As|Optional))
Der Ausdruck sucht nach einem der optionalen Schlüsselwörter (optionale Ausdrücke werden in Klammern eingefasst und durch das Pipe-Zeichen voneinander getrennt).
Das zweite Klammernpaar sorgt dafür, dass die Prozedur sich den Ausdruck merken kann.
Beim Ersetzen mit der Replace-Methode soll dann der entsprechende Ausdruck wiederverwendet und um das führende \@ ergänzt werden.
Wenn Sie die Prozedur gleich mit einer kompletten VBA-Routine durchexerzieren möchten, brauchen Sie einen Verweis auf die Bibliothek Microsoft Visual Basic for Applications Extensibility 5.3. Sie können dann mit der folgenden Funktion auf den Code eines Moduls zugreifen:
Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...
Testzugang
eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel
diesen und alle anderen Artikel mit dem Jahresabo