Reguläre Ausdrücke / RegExp

  • Speziell zu dem Thema "Schnellvorlagen" ist immer wieder die Rede von regulären Ausdrücken, Regular Expressions oder verkürzt RegExp.


    Was ist RegExp?

    Grundsätzlich ist ein RegExp einfach nur eine Art Suchbegriff. Man kann also damit weder Suchen noch Ersetzen. Dies geht nur über Plugins, z. B. XMP, oder über einen entsprechenden Aufbau der Vorlage, damit wollen wir uns in einem späteren Beispiel beschäftigen. Beispiele für XMP gibt es in dessen Hilfe.


    Welche Programme benötigt man?

    Damit man mit RegExp ordentlich arbeiten kann, benötigt man zuerst einmal ein Programm, welches die Ergebnisse der Suchanfrage ordentlich darstellen kann.

    Als Empfehlung (es gibt natürlich noch viele andere) möchte ich hier das kostenlose Kodos nennen, welches für diverse Betriebssysteme (Windows, Linux) verfügbar ist.

    Wer nur ein kleines Programm benötigt, dem ist für den Anfang sicher auch mit RegExpTest von Dirk Heiser geholfen. Dessen Homepage ist leider nicht mehr verfügbar, das Programm liegt jedoch als Anhang zu dem Beitrag bei. Die zip-Datei kann man einfach entpacken und das Programm über die Datei run.bat starten. Bitte lies dir auch die beiliegende readme.txt durch!

    Im Weiteren werde ich mit dem Programm RegExpTest arbeiten, da dieses für Anfänger wohl reichen wird, portabel und klein ist. Wer öfters mit RegExp arbeitet, wird später vielleicht dann lieber ein umfangreicheres Programm nehmen, aber für unsere Zwecke reicht das kleine erst mal.

    Wenn man das Programm gestartet hat, sollte man zuerst auf Optionen - Vorgaben gehen und dort (TB!) In Vorlagen auswählen, damit die gleichen Regeln wie in The Bat! gelten.

    Danach kann man das Fenster wieder mit OK schließen.


    Und jetzt? Ein kleines allgemeines Beispiel!

    Daher nehmen wir den folgenden Text einfach mal als Mail an, die wir bekommen haben.

    Code
    Name: Max Mustermann
    Mail: max@example.org
    WWW: http://www.example.org


    Diese Vorlage kann man sich erstmal kopieren und im Programm in das Feld "Zu prüfender Text:" einfügen.

    Wenn man nun im Feld "Reg. Ausdruck:" den Text Max Mustermann eingibt, erscheint im Feld "Untermuster:" im Register 0 ebenfalls der Text Max Mustermann, es wurde also der korrekte Text gefunden. Gibt man statt dessen Max Musterfrau ein, steht unter dem Suchbegriff "kein Treffer", da der Suchtext nicht im zu prüfenden Text vorhanden ist. Soweit noch logisch ;) Das gleiche Spielchen kann man nur für beliebige andere Text wiederholen.

    Natürlich hilft das nicht viel weiter, denn man kennt den Namen des Absenders ja normalerweise nicht. Dafür brauchen wir dann ein paar Platzhalter, mit denen wir variabler suchen können.


    wichtige Platzhalter in RegExp

    Beziehen wir uns wieder für ein besseres Verständnis auf unser vorheriges Beispiel. Gibt man \w+ als Suchbegriff ein, erscheint im Ergebnisfenster Name, da dies der erste Treffer ist, bei dem mindestens ein Buchstabe sich wiederholt. Durch das Plus werden alle weiteren Buchstaben ausgegeben, bis ein Zeichen kommt, das nicht auf \w zutrifft, in diesem Fall der Doppelpunkt.

    Wollen wir etwas tiefer in die Materie einsteigen.


    komplexere Suchabfragen

    Als nächstes wollen wir versuchen, die komplette erste Zeile auszulesen.
    Damit der entsprechende Bereich im Ergebnisfenster gezeigt wird, kann man natürlich Name: Max Mustermann eingeben, allerdings scheitert man spätestens bei Musterfrau wieder am Ergebnis ;)

    Will man die Zeile vereinfachen, muss man sich zwangsläufig überlegen, welche möglichen anderen Zeichen an bestimmten stellen vorkommen können. Im Fall des Namens können das neben üblichen Buchstaben auch Bindestriche, Punkte oder vielleicht auch Zahlen (Friedrich der 14te ;)) sein.

    Solche Zeichengruppen kann man in eckigen Klammern zusammenfassen. Für den Namen könnte man sich folgendes Suchmuster aufbauen:

    Code
    Name: [\w\d\.\,\-\ ]+$


    Liest man sich den Code durch, ist das an sich recht verständlich. Erst muss Name: im Text stehen, gefolgt von einem Leerzeichen (gegebenenfalls kann man statt dem Leerzeichen auch \s schreiben). Danach kommt eine Liste von möglichen Zeichen, von denen (wegen dem Plus) mindestens einmal eines vorhanden sein muss. Als mögliche Zeichen können Buchstaben (\w), Zahlen (\d), Komma, Bindestriche oder Leerzeichen vorhanden sein. Nach diesen möglichen Zeichen muss ein Zeilenende kommen.

    Im Ergebnisfenster steht jetzt immer noch als gefundener Text Name: Max Mustermann. Ändert man jedoch im Feld "Zu prüfender Text:" den Namen, ändert sich auch das Suchergebnis, ohne das man den regulären Ausdruck anpassen muss. Die schwerste Arbeit ist damit schon gemacht :)

    Wer übrigens auf die Idee kommt, einfach

    Code
    Name: .*


    (Name: gefolgt von beliebig vielen Zeichen, ein beliebter Platzhalter) zu benutzen, sollte hier vorsichtig sein. Denn .* findet rigoros alle Zeichen bis zum Ende, sofern es zwischendurch, bzw. in der Suchanfrage, keine eindeutigen Trenner gibt. Es hört also nicht am Zeilenende auf, sondern am Textende. Eine genauere Erklärung zu diesem Verhalten gibt es im zweiten Beitrag.


    Und wie kann ich jetzt nur den Namen auslesen?

    Das geht (wenn man das RegExp korrekt aufgebaut hat, jetzt ganz einfach. Man braucht einfach nur runde Klammern um den benötigten Begriff setzen.

    Code
    Name: ([\w\d\.\,\-\ ]+)$


    Im Register 0 hat sich jetzt nichts geändert, da hier immer das komplette Ergebnis der Suche angezeigt wird, jedoch ist ein neues Register 1 erschienen. In diesem Register findet sich nun nur der Inhalt dieser (ersten) runden Klammer. Mit jeder weiteren Klammerung erhält man ein weiteres Register, in dem nur der Inhalt dieser Klammer angezeigt wird.

    Die jeweilige Klammer-Nummer benötigt man später noch für The Bat!, man sollte also prüfen ob und in welcher Klammer die richtigen/benötigten Ergebnisse stehen.


    Wie bekomme ich die restlichen Informationen aus dem Text?

    Man könnte sich für die Mail- und Internet-Adresse wieder mit komplizierten Suchabfragen behelfen und manchmal ist dies auch nötig, je nachdem wie der Vorgabetext aufgebaut ist. Unser Beispiel ist jedoch recht einfach gehalten, so dass man etwas vereinfachen kann.

    Man kann den Beispieltext im Wortlaut einfach mal durchgehen:

    • Am Zeilenanfang steht Name:, danach ein beliebiger Text, dann kommt ein Zeilenumbruch.
    • Am Zeilenanfang steht Mail:, danach ein beliebiger Text, dann kommt ein Zeilenumbruch.
    • Am Zeilenanfang steht WWW:, danach ein beliebiger Text, dann kommt ein Zeilenende.

    Zu beachten ist, dass die letzte Zeile ein Zeilenende hat und keinen Zeilenumbruch. Das kann man ganz leicht prüfen, indem man versucht mit dem Cursor in eine Zeile 4 zu springen, diese ist in meinem Beispiel nicht vorhanden.

    Als RegExp-Code würde das wie folgt aussehen:

    Code
    ^Name: .*\n
    ^Mail: .*\n
    ^WWW: .*$

    Zu beachten ist hier wieder der Platzhalter .*, mit dem man vorsichtig umgehen muss, da dieser unter Umständen mehr findet als er eigentlich soll. In diesem Fall muss man dann die Suche über Zeichengruppen (die eckigen Klammern) evtl. genauer eingrenzen.

    Den vorherigen Code muss man jetzt nur noch in eine einzelne Zeile ziehen:

    Code
    ^Name: .*\n^Mail: .*\n^WWW: .*$


    Gibt man diesen in RegExTest ein, sollte im Register 0 wieder nur der komplette Beispieltext stehen. Das ist soweit korrekt, da damit schon mal der Aufbau des RegExp stimmt.

    Nun muss man nur noch an die einzelnen Informationen gelangen. Dies erreicht man, wie oben bereits beschrieben, durch das setzen von runden Klammern um die jeweiligen Such-Abschnitte, welche man benötigt:

    Code
    ^Name: (.*)\n^Mail: (.*)\n^WWW: (.*)$


    Achte beim setzen der Klammern darauf, dass das Leerzeichen vor der öffnenden Klammer ist, da sonst im Suchergebnis das Leerzeichen ebenfalls für die spätere Verwendung mitgenommen wird.

    Im RegExTest sollten nun die Register 1-3 mit den einzelnen Ergebnissen zu Name, E-Mail und WWW vorhanden sein.


    Wie verwende ich die Sachen nun in The Bat?

    Zuerst einmal legt man sich eine (Schnell-)Vorlage an, in der man das RegExp verwenden will.

    Das benutzen des RegExp in The Bat! ist eigentlich relativ einfach, da der Aufbau immer der gleiche ist:

    Code
    %setpattregexp='hier steht das RegExp'%-
    %RegExpBlindMatch(hier steht der zu durchsuchende Text)%-
    %SubPatt='1'
    • In der ersten Zeile muss man das RegExp einfügen, welches man vorher in RegExTest gebastelt hat.
    • In der zweiten Zeile muss man in die Klammern den Text schreiben, den man durchsuchen will. Hier kann man z. B. %TEXT für den Text der Original-Mail verwenden oder auch %OFromAddr und was es sonst so gibt. Eine umfangreiche Übersicht dazu findet man auf thebatworld.de
    • In der dritten Zeile kann man dann die gefundenen Texte ausgeben lassen. Die Zahl entspricht dabei dem Register, in welchem in RegExTest das gesuchte Ergebnis steht.

    In unserem Beispiel würde das so aussehen:

    Code
    %setpattregexp='^Name: (.*)\n^Mail: (.*)\n^WWW: (.*)$'%-
    %RegExpBlindMatch(%TEXT)%-
    %SubPatt='1'
    %SubPatt='2'
    %SubPatt='3'

    Wenn man nun auf eine Mail (in der unser angenommener Mustertext steht) antwortet und die Schnellvorlage aufruft, erscheint im Mail-Text unserer neuen Mail

    Code
    Max Mustermann
    max@example.org
    http://www.example.org

    Damit man nun an den richtigen schreibt, könnte man z. B. auch die E-Mail-Adresse gleich in den Empfänger schreiben lassen:

    Code
    %SETHEADER("TO","%SubPatt='2'")%-

    Der Rest ist dann Geschmackssache :)

  • Erläuterung zu GREEDY bzw. UNGREEDY

    The Bat! arbeitet normalerweise GREEDY, was die Übersetzung "gierig" wohl recht gut beschreibt. Was man sich darunter vorstellen muss? Ein einfaches Beispiel soll es verdeutlichen.

    Als Mustertext verwenden wir

    Code
    <tr><td>Zeile 1</td></tr>
    <tr><td>Zeile 2</td></tr>
    <tr><td>Zeile 3</td></tr>

    Als Suchbegriff wird Folgendes verwendet:

    Code
    <td>(.*)</td>

    Als Ergebnis erhält man für Untermuster 1:

    Code
    Zeile 1</td></tr>
    <tr><td>Zeile 2</td></tr>
    <tr><td>Zeile 3

    Das Suchmuster .* schnappt sich also alles bis zum letzten Vorkommen von </td>, was unter Umständen nicht gewollt sein kann.

    Um dieses Verhalten zu ändern, muss man die Suchabfrage wie folgt ändern:

    Code
    <td>(.*?)</td>

    Nun erhält man als Untermuster 1 nur noch

    Code
    Zeile 1


    .* sucht wegen dem ? (Umschalter für greedy/ungreedy) nur noch bis zum ersten Vorkommen von </td>


    Nehmen wir nochmals unser Beispiel aus dem vorherigen Beitrag her.

    Als Mustertext hatten wir

    Code
    Name: Max Mustermann
    Mail: max@example.org
    WWW: http://www.example.org

    Als Suche hatten wir uns

    Code
    Name: ([\w\d\.\,\-\ ]+)$


    entwickelt, da .* normalerweise zu viel erfassen würde.

    Das können wir ja nochmals versuchen, also als Suchbegriff

    Code
    Name: (.*)$


    eintragen, dann bekommen wir als Ergebnis

    Code
    Name: Max Mustermann
    Mail: max@example.org
    WWW: http://www.example.org


    da hinter example.org das letzte Zeilenende ($) des Textes kommt.

    Ändert man nun das RegExp ab, indem man den Ausdruck .* ungreedy setzt

    Code
    Name: (.*?)$


    wird jetzt auch nur noch bis zum ersten Vorkommen eines Zeilenendes ($) gesucht.

    Man erhält als Ergebnis also

    Code
    Max Mustermann


    Und damit ist unser kleiner Einführungskurs in RegExp und die Verwendung mit The Bat! abgeschlossen.

    Wer noch tiefer in die ganzen Dinge einsteigen möchte, dem sei regenechsen.de empfohlen, dort werden noch viele weitere Dinge und Möglichkeiten beschrieben.

  • GwenDragon 8. Juni 2022 um 17:03

    Hat das Thema geschlossen.