Personal Backup |
|
© 2001 − 2021, Dr. Jürgen Rathlev |
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.
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.
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.
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.
Code | Beschreibung | Äquivalenz |
\xnn | Zeichen 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 | |
\t | Tabulator (HT/TAB) | \x09 |
\n | Zeilenvorschub (LF) | \x0a |
\r | Wagenrücklauf (CR) | \x0d |
\f | Seitenvorschub (FF) | \x0c |
\a | Alarm (bell) (BEL) | \x07 |
\e | Escape (ESC) | \x1b |
Weitere Zeichen, die das Escape-Zeichen \ erfordern sind die Klammern () und [] und, wie bereits erwähnt, der "Backslash" \ selbst.
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.
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 \].
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.
Code | Beschreibung |
^ | Zeilenanfang |
$ | Zeilenende |
\A | Textanfang |
\Z | Textende |
. | ein beliebiges Zeichen |
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.
\w | ein alphanumerisches Zeichen inklusive "_" |
\W | kein alphanumerisches Zeichen, auch kein "_" |
\d | ein numerisches Zeichen |
\D | kein numerisches Zeichen |
\s | irgendein Wörter trennendes Zeichen (entspricht [ \t\n\r\f]) |
\S | kein Wörter trennendes Zeichen |
\w, \d und \s dürfen auch innerhalb von selbst definierten Zeichenklassen benutzt werden.
TRegExpr benutzt die Eigenschaften SpaceChars und WordChars, um die Zeichenklassen \w, \W, \s, \S zu definieren. Somit lassen diese sich auch leicht umdefinieren.
\b | findet eine Wortgrenze |
\B | findet 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.
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.
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.
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|].
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.
Die Metazeichen \1 bis \9 werden in Suchmustern als Rückwärtsreferenzen interpretiert. \<n> findet einen zuvor bereits gefundenen Teilausdruck #<n>.
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.
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: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.
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.