HTML-Tags erkennen

(Auszug aus "Reguläre Ausdrücke" von Jeffrey E. F. Friedl)

Man sieht oft den regulären Ausdruck ˹<[^>]+>˼, der ein HTML-Tag erkennen soll. Meist funktioniert das auch, zum Beispiel in diesem Perl-Programmstück:

$html =~ s/<[^>]+>//g;

Es gibt allerdings ein Problem, wenn innerhalb des Tags ein ›>‹ vorkommt, z.B. bei diesem völlig korrekten HTML-Tag: <img src=rechtspfeil.png alt=">">. Das ist nicht sehr häufig und wird auch nicht empfohlen, aber in einem Tag-Attribut dürfen durchaus ›<‹ oder ›>‹ vorkommen, sofern sie in Anführungszeichen stehen. Unser einfaches ˹<[^>]+>˼ berücksichtigt das nicht, also müssen wir es schlauer machen.

Innerhalb von ›<...>‹ sind Strings in Anführungszeichen erlaubt sowie »anderes Zeug«, das nicht in Anführungszeichen zu stehen braucht, nämlich alles außer ›>‹ und den Anführungszeichen. In HTML kann man für die Anführungszeichen wahlweise die Gänsefüßchen oder die Hochkommas nehmen, dagegen kann man diese einfachen oder doppelten Anführungszeichen nicht mit einem Backslash schützen. Wir können daher relativ einfache reguläre Ausdrücke wie ˹"[^"]*"˼ und ˹'[^']*'˼ verwenden.

Zusammen mit der Regex ˹[^'">]˼ für das »andere Zeug« erhalten wir:

˹<("[^"]*"|'[^']*'|[^'">])*

Das ist ziemlich verwirrend, darum zeige ich dasselbe noch einmal im Modus »Freie Form«:

<                # Öffnendes "<"
   (             #     Jede Anzahl von ...
       "[^"]*"   #        Strings in Anführungszeichen
       |         #        oder ...
       '[^']*'   #        Strings in Hochkommas
       |         #        oder ...
       [^'">]    #        "anderes Zeug".
   )*            #
>                # Schließendes ">"

Der Ansatz ist recht elegant. Jeder String in Anführungszeichen wird als Einheit betrachtet, und dabei wird klar gesagt, welche Zeichen an welcher Stelle erlaubt sind. Ein bestimmtes Zeichen kann immer nur auf eine Alternative passen, es gibt hier keine Mehrdeutigkeit, und so besteht auch keine Gefahr, dass sich hier wie bei früheren Beispielen plötzlich ungewollte Treffer einschleichen.

In den ersten zwei Alternativen wird ˹*˼ und nicht ˹+˼ benutzt, denn ein String in Hochkommas oder Anführungszeichen darf auch leer sein (z.B. ›alt=""‹). Dagegen darf in der dritten Alternative weder ˹*˼ noch ˹+˼ auftreten, denn einen Quantor gibt es schon für die Klammer, die die Alternation umschließt. Mit einem weiteren Quantor, beispielsweise mit ˹([^'">]+)*˼, bekämen wir eine böse Überraschung, auf die ich unter Die Kunst, reguläre Ausdrücke zu schreiben im Detail eingehe (siehe unter Gieriges Verhalten nur lokal zulassen).

Noch einige Überlegungen zur Effizienz bei einem NFA: Wenn wir den von den Klammern eingefangenen Text nicht benötigen, können wir die Klammern durch nicht-einfangende Klammern ersetzen (siehe Nur gruppierende (nicht-einfangende) Klammern). Weil es keine Mehrdeutigkeiten zwischen den Alternativen gibt, ist ein erneutes Ausprobieren der anderen Alternativen sinnlos, wenn das ˹>˼ am Ende nicht gefunden wird. Wenn eine Alternative gepasst hat, kann an der gleichen Stelle keine der anderen passen. Wir können deshalb die gespeicherten Zustände ohne Schaden wegwerfen; sie würden ohnehin nur zu Fehlschlägen führen. Wir können also die nicht-einfangenden Klammern auch durch ˹(?>...)˼, also durch atomare Klammern, ersetzen (oder sie mit einem possessiven Stern quantisieren).

  

<< zurück vor >>

 

 

 

Tipp der data2type-Redaktion:
Zum Thema Reguläre Ausdrücke bieten wir auch folgende Schulungen zur Vertiefung und professionellen Fortbildung an:
   

Copyright der deutschen Ausgabe © 2008 by O’Reilly Verlag GmbH & Co. KG
Für Ihren privaten Gebrauch dürfen Sie die Online-Version ausdrucken.
Ansonsten unterliegt dieses Kapitel aus dem Buch "Reguläre Ausdrücke" denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

O’Reilly Verlag GmbH & Co. KG, Balthasarstr. 81, 50670 Köln