Inhaltsverzeichnis
PersBackup

Personal Backup

© 2001 − 2021, Dr. Jürgen Rathlev

Reguläre Ausdrücke mit Personal Backup

Im Programm können reguläre Ausdrücke für die Filterung von Ordnernamen, Dateinamen und Erweiterungen verwendet werden. Dabei gibt es unterschiedliche Voreinstellungen:

Mit dem Modifikator (?i) kann diese Einstellung bei Bedarf angepasst werden.

Personal Backup 6.1 verwendet für die Auswertung der regulären Ausdrücke die Delphi-Klasse TPerlRegEx.

Eine ausführliche englische Beschreibung der Syntax von regulären Ausdrücken, sowie Beispiele und Anleitungen findet man bei Regular-Expressions.info. Eine kurze Übersicht über die Syntax ist nachfolgend wiedergegeben.


Einführung

Reguläre Ausdrücke sind eine weit verbreitete Methode, um Textmuster zu beschreiben, nach denen gesucht werden soll. Spezielle Metazeichen erlauben die Definition von Bedingungen, um z.B. eine bestimmte Zeichenfolge zu suchen, wenn sie am Anfang oder am Ende einer Zeile vorkommt, oder ein bestimmtes Zeichen zu suchen, das genau n-mal vorkommt.

Reguläre Ausdrücke sehen üblicherweise für Anfänger ziemlich kryptisch aus, sind aber im Grunde genommen recht einfache (wenn man das Prinzip verstanden hat), aber enorm mächtige Werkzeuge.

Einfache Treffer

Jedes einzelne Zeichen findet sich selbst, außer es ist ein Metazeichen mit einer speziellen Bedeutung (siehe weiter unten).

Eine Sequenz von Zeichen findet genau diese Sequenz im zu durchsuchenden Text (Zielstring). Also findet das Muster (= regulärer Ausdruck) bluh genau die Sequenz bluh irgendwo im Zielstring existiert. Soweit ist das noch ganz einfach.

Damit man Zeichen, die üblicherweise als Metazeichen oder Escape-Sequenzen dienen, als ganz normale Zeichen ohne jede Bedeutung finden kann, stellt man diesen Zeichen das sog. Escape-Zeichen \ voran. Ein Beispiel: Das Metazeichen ^ findet den Anfang des Zielstrings, aber \^ findet das Zeichen ^ (Zirkumflex), \\ findet also \ etc.

Beispiele:
foobar      findet die Zeichenfolge foobar
\^FooBarPtr findet die Zeichenfolge ^FooBarPtr

Escape-Sequenzen

Zeichen können auch mittels einer Escape-Sequenz angeben werden. Die Syntax ähnelt derer, wie sie in C oder Perl verwendet wird: \n findet eine neue Zeile, \t einen Tabulator etc.
Für beliebige ASCII-Zeichen gibt man \xnn an, wobei nn eine Zeichenfolge aus zwei hexadezimalen Ziffern ist. Es wird das Zeichen gefunden, dessen ASCII Code gleich nn ist. Bei Unicode-Zeichen (16 Bit kodierte Zeichen) verwendet man \x{nnnn}, wobei nnnn bis zu vier hexadezimale Ziffern sind, die dem Unicode-Zeichen entsprechen.

CodeBeschreibungÄquivalenz
\xnnZeichen mit dem Hex-Code nn (ASCII-Text) 
\x{nnnn}Zeichen mit dem Hex-Code nnnn (ein Byte für ASCII-Text
und zwei Bytes für Unicode-Zeichen
 
\tTabulator (HT/TAB)\x09
\nZeilenvorschub (LF)\x0a
\rWagenrücklauf (CR)\x0d
\fSeitenvorschub (FF)\x0c
\aAlarm (bell) (BEL)\x07
\eEscape (ESC)\x1b
Beispiele:
foo\x20bar findet foo bar (beachte das Leerzeichen in der Mitte)
\tfoobar   findet foobar, dem unmittelbar ein Tabulator vorangeht

Weitere Zeichen, die das Escape-Zeichen \ erfordern sind die Klammern () und [] und, wie bereits erwähnt, der "Backslash" \ selbst.

Zeichenklassen

Man kann sogenannte Zeichenklassen definieren, indem man eine Liste von Zeichen, eingeschlossen in eckige Klammern [], angibt. Solch eine Zeichenklasse findet genau eines der aufgeführten Zeichen im Zielstring.

Wenn das erste aufgeführte Zeichen, das direkt dem [ folgt, ein ^ ist, findet die Zeichenklasse alle Zeichen, die nicht in der Liste stehen.

Beispiele:
foob[aeiou]r  findet die Zeichenketten foobar, foober etc. aber nicht foobbr, foobcr etc.
foob[^aeiou]r findet die Zeichenketten foobbr, foobcr etc. aber nicht foobar, foober etc.

Innerhalb der Liste kann das Zeichen - benutzt werden, um einen Bereich oder eine Menge von Zeichen zu definieren. So definiert a-z alle Zeichen von a bis z.

Falls das Zeichen - selbst ein Mitglied der Zeichenklasse sein soll, dann setzt man es als erstes oder letztes Zeichen in die Liste oder schützt es mit einem vorangestellten Escape-Zeichen \. Wenn das Zeichen ] ebenfalls Mitglied der Zeichenklasse sein soll, dann setzt man es als erstes Zeichen in die Liste oder als \].

Beispiele:
[-az]     findet a, z und -
[az-]     findet a, z und -
[a\-z]    findet a, z und -
[a-z]     findet alle 26 Kleinbuchstaben von a bis z
[\n-\x0D] findet eines der Zeichen #10, #11, #12 oder #13
[\d-t]    findet irgendeine Ziffer, - oder t
[]-a]     findet irgendein Zeichen von ] bis a

Metazeichen

Metazeichen sind Zeichen mit speziellen Bedeutungen. Sie sind das wichtigste Werkzeug der regulären Ausdrücke. Es gibt verschiedene Arten von Metazeichen wie nachfolgend beschrieben.

Metazeichen - Zeilenseparatoren

Code Beschreibung
^Zeilenanfang
$Zeilenende
\ATextanfang
\ZTextende
.ein beliebiges Zeichen
Beispiele:
^foobar  findet die Zeichenkette foobar nur, wenn es am Zeilenanfang vorkommt
foobar$  findet die Zeichenkette foobar nur, wenn es am Zeilenende vorkommt
^foobar$ findet die Zeichenkette foobar nur, wenn er der einzige String in der Zeile ist
foob.r   findet Zeichenketten wie foobar, foobbr, foob1r etc.

Standardmäßig garantiert das Metazeichen ^ einen Sucherfolg nur, wenn das Suchmuster sich am Anfang des zu durchsuchenden Textes befinden muss, beim Metazeichen $ entsprechend am Ende des Textes. Im Text eingebundene Zeilenseparatoren, werden von ^ oder $ nicht gefunden.

Wird allerdings der Modifikator (?m) eingeschaltet, so wird der Text als mehrzeilig behandelt. Dadurch findet ^ auch jede Stelle unmittelbar nach und $ jede Stelle unmittelbar vor irgendeinem Zeilenseparator.

\A und \Z funktionieren genau so wie ^ und $, außer dass auch bei eingeschaltetem Modifikator (?m) keine mehrfachen Stellen gefunden werden. ^ und $ dagegen finden die zu suchenden Zeichen auch an jedem Zeilenseparator.

Das . Metazeichen findet standardmäßig alle Zeichen. Zeilenseparatoren werden nur gefunden, wenn der Modifikator (?s) eingeschaltet ist.

TRegExpr geht mit Zeilenseparatoren so um, wie es auf www.unicode.org empfohlen wird:

^ am Anfang der Such-Zeilenkette: Bei eingeschaltetem Modifikator (?m) werden alle Stellen im Text gefunden, die den Zeichen \x0D\x0A, \x0A oder \x0D folgen. Wird die Unicode-Version von TRegExpr verwendet, dann werden auch die Stellen nach \x2028, \x2029, \x0B, \x0C oder \x85 gefunden. Zu beachten ist, dass es bei der Sequenz \x0D\x0A keine leere Zeile dazwischen gibt. Diese beiden Zeichen werden als zusammengehörig behandelt.

$ am Anfang der Such-Zeilenkette: Bei eingeschaltetem Modifikator (?m), werden alle Stellen gefunden, die den Zeichen \x0D\x0A, \x0A oder \x0D vorangehen. Wird die Unicode-Version von TRegExpr verwendet, dann werden auch die Stellen vor \x2028, \x2029, \x0B, \x0C oder \x85 gefunden. Zu beachten ist, dass es bei der Sequenz \x0D\x0A keine leere Zeile dazwischen gibt. Diese beiden Zeichen werden als zusammengehörig behandelt.

. findet ein beliebiges Zeichen: Bei ausgeschaltetem Modifikator (?s) werden keine Zeilenseparatoren wie \x0D\x0A, \x0A und \x0D gefunden. Wird die Unicode-Version von TRegExpr verwendet, dan gilt das auch für \x2028, \x2029, \x0B, \x0C und \x85.

Zu beachten ist, dass ^.*$ (das Muster für eine leere Zeile) die leere Zeilenkette innerhalb der Sequenz \x0D\x0A nicht findet, wohl aber eine leere Zeilenkette der Sequenz \x0A\x0D.

Die Behandlung des Textes als mehrzeilig kann mittels der TRegExpr-Eigenschaften LineSeparators und LinePairedSeparator leicht den erforderlichen Bedürfnissen angepasst werden. Man kann entweder nur den UNIX-Stil- Zeilenseparator \n benutzen, nur die DOS-Stil-Separatoren \r\n oder beide gleichzeitig (wie schon oben beschrieben und wie es als Standard gesetzt ist). Es ist auch möglich, eigene Zeilenseparatoren zu definieren.

Metazeichen - vordefinierte Klassen

\wein alphanumerisches Zeichen inklusive "_"
\Wkein alphanumerisches Zeichen, auch kein "_"
\dein numerisches Zeichen
\Dkein numerisches Zeichen
\sirgendein Wörter trennendes Zeichen (entspricht [ \t\n\r\f])
\Skein Wörter trennendes Zeichen

\w, \d und \s dürfen auch innerhalb von selbst definierten Zeichenklassen benutzt werden.

Beispiele:
foob\dr     findet Zeilenketten wie foob1r, foob6r etc., aber nicht foobar, foobbr etc.
foob[\w\s]r findet Zeilenketten wie foobar, foob r, foobbr etc., aber nicht foob1r, foob=r etc.

TRegExpr benutzt die Eigenschaften SpaceChars und WordChars, um die Zeichenklassen \w, \W, \s, \S zu definieren. Somit lassen diese sich auch leicht umdefinieren.

Metazeichen - Wortgrenzen

\bfindet eine Wortgrenze
\Bfindet alles außer einer Wortgrenze

Eine Wortgrenze \b ist der Ort zwischen zwei Zeichen, bei denen auf der einen Seite ein \w und auf der anderen ein \W steht (s.o.) oder umgekehrt. \b. Es beinhaltet alle Zeichen beginnend vom \w bis zum ersten Zeichen vor dem \W oder umgekehrt.

Metazeichen - Iteratoren

Jedem Teil eines regulären Ausdruckes kann ein spezieller Typ von Metazeichen folgen, ein Iterator. Dank dieser Metazeichen kann die Häufigkeit des Auftretens des Suchmusters im Text definiert werden. Dies gilt jeweils für das vor diesem Metazeichen stehende Zeichen, Metazeichen oder den Teilausdruck.

{n}genau n-maliges Vorkommen ("gierig")
{n,}mindestens n-maliges Vorkommen ("gierig")
{n,m}mindestens n-, aber höchstens m-maliges Vorkommen ("gierig")
*kein- oder mehrmaliges Vorkommen ("gierig"), wie {0,}
+ein- oder mehrmaliges Vorkommen ("gierig"), wie {1,}
?kein- oder einmaliges Vorkommen ("gierig"), wie {0,1}
{n}?genau n-maliges Vorkommen ("genügsam")
{n,}? mindestens n-maliges Vorkommen ("genügsam")
{n,m}?mindestens n-, aber höchstens m-maliges Vorkommen ("genügsam")
*?kein- oder mehrmaliges Vorkommen ("genügsam"), wie {0,}?
+?ein oder mehrmaliges Vorkommen ("genügsam"), wie {1,}?
??kein- oder einmaliges Vorkommen ("genügsam"), wie {0,1}?

Die Ziffern in den geschweiften Klammern in der Form {n,m} geben an, wie viele Male das Suchmuster im Text gefunden werden muss, um einen Treffer zu ergeben. Die Angabe {n} ist gleichbedeutend wie {n,n} und findet genau n Vorkommen. Die Form {n,} findet n oder mehre Vorkommen. Es gibt keine Beschränkungen für die Zahlen n und m. Aber je größer sie sind, desto mehr Speicher und Zeit wird benötigt, um den regulären Ausdruck auszuwerten.

Falls eine geschweifte Klammer in einem anderen als dem eben vorgestellten Kontext vorkommt, wird sie wie ein normales Zeichen behandelt.

Beispiele:
foob.*r    findet Zeilenketten wie foobar, foobalkjdflkj9r und foobr
foob.+r    findet Zeilenketten wie foobar, foobalkjdflkj9r, aber nicht foobr
foob.?r    findet Zeilenketten wie foobar, foobbr und foobr, aber nicht foobalkj9r
fooba{2}r  findet die Zeilenkette foobaar
fooba{2,}r findet Zeilenkette wie foobaar, foobaaar, foobaaaar etc.
fooba{2,3} findet Zeilenketten wie foobaar oder foobaaar, aber nicht foobaaaar

Eine kleine Erklärung zum Thema "gierig" und "genügsam":
"Gierig" nimmt soviel wie möglich vom Suchmuster, wohingegen "genügsam" mit so wenig wie nötig bereits zufrieden ist.
Beispiel für den zu durchsuchenden Text abbbbc:
b+ und b* ergeben bbbb
b+? ergibt b
b*? ergibt eine leeren Zeilenkette
b{2,3}? ergibt bb
b{2,3} ergibt bbb.

Alle Iteratoren können mit dem Modifikator (?g) auf den genügsamen Modus umgeschaltet werden.

Metazeichen - Alternativen

Eine Reihe von alternativen Angaben für ein Suchmuster wird jeweils mit einem | voneinander getrennt. Auf diese Art findet das Suchmuster fee|fie|foe eines der Vorkommen von fee, fie oder foe im Text. Das Gleiche würde man auch mit f(e|i|o)e erreichen können.

Die erste Angabe für eine Alternative beinhaltet alle Zeichen vom letzten Muster-Begrenzer ( oder [ oder dem Anfang des Suchmusters bis zum ersten |. Die letzte Angabe beinhaltet alles vom letzten | bis zum nächsten darauf folgenden Muster-Begrenzer. Aus diesem Grunde ist es zu empfehlen, die Alternativen immer in Klammern anzugeben, um möglichen Missverständnissen darüber vorzubeugen, wo die Alternativen beginnen und enden.

Alternative Angaben werden von links nach rechts verarbeitet, so dass der Treffer im Text aus den jeweils zuerst passenden Alternativen zusammengesetzt ist. Das bedeutet, dass Alternativen nicht notwendigerweise "gierig" sind. Ein Beispiel: Wenn man mit (foo|foot) den Text barefoot durchsucht, so passt bereits die erste Angabe. Diese Tatsache mag nicht besonders wichtig erscheinen, aber es ist natürlich wichtig, wenn der gefundene Text zwischengespeichert wird, um ihn wieder zu verwenden (siehe hier).

Man sollte auch nicht vergessen, dass das | innerhalb von eckigen Klammern wie ein normales Zeichen behandelt wird, so dass [fee|fie|foe] dasselbe bedeutet wie [feio|].

Beispiel:
foo(bar|foo) findet die Zeilenketten foobar oder foofoo

Metazeichen - Teilausdrücke

Die Einklammerung mit (...) wird auch dazu benutzt, um Teilausdrücke zu definieren. Im Programm findet man nach der Analyse des Ausdrucks die Positionen, Längen und effektive Inhalte der regulären Teilausdrücke in den TRegExpr-Eigenschaften MatchPos, MatchLen und Match und kann die Schablonen-Ausdrücke in TRegExpr.Substitute durch sie ersetzen.

Teilausdrücke werden von links nach rechts nummeriert, jeweils in der Reihenfolge ihrer öffnenden Klammer. Der erste Teilausdruck hat die Nummer 1. Der gesamte reguläre Ausdruck hat die Nummer 0 und wird in der Ersetzen-Schablone (TRegExpr.Substitute) durch $0 oder $& repräsentiert.

Beispiele:
(foobar){8,10}  findet Zeilenketten, die 8, 9 oder 10 Vorkommen von foobar enthalten
foob([0-9]|a+)r findet foob0r, foob1r foobar, foobaar, foobaar etc.

Metazeichen - Rückwärtsreferenzen

Die Metazeichen \1 bis \9 werden in Suchmustern als Rückwärtsreferenzen interpretiert. \<n> findet einen zuvor bereits gefundenen Teilausdruck #<n>.

Beispiele:
(.)\1+         findet aaaa und cc.
(.+)\1+        findet auch abab und 123123
(['"]?)(\d+)\1 findet "13" (mit Anführungszeichen), oder '4' (Mit Apostrophs) oder auch 77, etc.

Modifikatoren

Modifikatoren sind dazu da, das Verhalten von TRegExpr zu verändern.

Es gibt viele Möglichkeiten, die weiter unten beschriebenen Modifikatoren zu nutzen. Jeder der Modifikatoren kann in das Suchmuster des regulären Ausdruckes mittels des Konstruktes (?...) eingebunden werden.

Die meisten Modifikatoren können aber auch durch Setzen der entsprechenden TRegExpr-Eigenschaft im Programm auf den gewünschten Wert geändert werden (Beispiel: Zuweisung an ModifierX oder ModifierStr für alle Modifikatoren zugleich).

Die Standardwerte für neue Instanzen von TRegExpr-Objekte sind als globalen Variablen im Programm definiert, z.B. legt die globale Variable RegExprModifierX das Verhalten des Modifikators X und damit die Einstellung der TRegExpr-Eigenschaft ModifierX bei neu instantiierten TRegExpr-Objekten fest.

(?i)

Die Suche erfolgt ohne Berücksichtigung der Groß- und Kleinschreibung (evtl. abhängig von den Sprach-Einstellungen des Betriebssystems).

(?-i)

Die Suche erfolgt mit Berücksichtigung der Groß- und Kleinschreibung.

(?m)

Behandle den zu durchsuchenden Text als mehrzeilig, d.h. die Bedeutungen von ^ und $ ändern sich (siehe auch):
Statt die Zeichenkette nur am Anfang oder am Ende des Textes zu finden, wird jeder Zeilenseparator innerhalb des Textes erkannt.

(?s)

Behandle den durchsuchenden Text als einzelne Zeile, d.h., dass . jedes beliebige Zeichen findet, auch Zeilenseparatoren), die es normalerweise nicht findet.

(?-g)

Dieser (nicht-standard) Modifikator schaltet alle folgenden Operatoren in den "Genügsam"-Modus (standardmäßig sind alle Operatoren "gierig"). Danach arbeitet+ wie +? und * wie *? etc.

(?r)

Dieser (nicht-standard) Modifikator schaltet in einen speziellen Modus für russische Symbole (In Personal Backup normalerweise ausgeschaltet).

(?x)

Erweitert die Lesbarkeit des Suchmusters durch Zwischenräume und Kommentare. Er bewirkt, dass alle Zwischenräume, die nicht durch eine Escape-Sequenz oder innerhalb einer Zeichenklasse gekennzeichnet sind, ignoriert werden. Man kann damit den regulären Ausdruck in kleinere, besser lesbare Teile zerlegen. Das Zeichen # wird als Metazeichen behandelt und leitet einen Kommentar bis zum Zeilenende ein.

Beispiel:
(
(abc) # Kommentar 1
  |   # man kann Zwischenräume zur Formatierung benutzen - TRegExpr ignoriert sie
(efg) # Kommentar 2
)

Wenn man also echte Zwischenräume oder das # im Suchmuster benötigt, (außerhalb einer Zeichenklasse, wo sie wegen des Modifikators (?x) nicht ignoriert werden), muss das entweder durch Voranstellen des Escape-Zeichens \ oder durch Angabe in der hexadezimalen Schreibweise erfolgen. Beides zusammen sorgt dafür, dass reguläre Ausdrücke besser lesbar werden.

Beispiele:
(?i)Sankt-Petersburg      findet Sankt-petersburg und Sankt-Petersburg
(?i)Sankt-(?-i)Petersburg findet Sankt-Petersburg, aber nicht Sankt-petersburg
(?i)(Sankt-)?Petersburg   findet Sankt-petersburg und sankt-petersburg
((?i)Sankt-)?Petersburg   findet sankt-Petersburg, aber nicht sankt-petersburg

Sonstiges

(?#text)

Ein Kommentar, der Text wird ignoriert. Zu beachten ist, dass TRegExpr die nächste schließende Klammer ) als Ende des Kommentars ansieht. Es gibt daher keine Möglichkeit, die Klammer im Kommentar zu verwenden.


J. Rathlev, D-24222 Schwentinental, Oktober 2020