Verwenden von regulären Ausdrücken zum Parsen von HTML: Warum nicht?

207

Es scheint, dass jede Frage zum Stackoverflow, bei der der Fragesteller Regex verwendet, um Informationen aus HTML abzurufen, unweigerlich eine "Antwort" hat, die besagt, dass Regex nicht zum Parsen von HTML verwendet werden soll.

Warum nicht? Ich bin mir bewusst, dass es "echte" HTML-Parser wie Beautiful Soup gibt , und ich bin sicher, dass sie leistungsstark und nützlich sind, aber wenn Sie nur etwas Einfaches, Schnelles oder Schmutziges tun, warum dann? sich die Mühe machen, etwas so Kompliziertes zu verwenden, wenn ein paar Regex-Anweisungen gut funktionieren?

Gibt es darüber hinaus nur etwas Grundlegendes, das ich über Regex nicht verstehe, was sie zu einer schlechten Wahl für das Parsen im Allgemeinen macht?

ntownsend
quelle
3
Ich denke, dies ist ein Betrug von stackoverflow.com/questions/133601
jcrossley3
23
Weil nur Chuck Norris HTML mit Regex analysieren kann (wie in dieser berühmten Zalgo-Sache erklärt: stackoverflow.com/questions/1732348/… ).
Takeshin
1
Diese Frage veranlasste mich, eine andere zu stellen, die irgendwie verwandt ist. Falls Sie interessiert sind: Warum es nicht möglich ist, Regex zum Parsen von HTML / XML zu verwenden: eine formale Erklärung für Laien
Mac
Vorsicht vor Zalgo
Kelly S. French
Diese Frage wurde zu den häufig gestellten Fragen zum regulären Überlauf des Stapelüberlaufs unter "Allgemeine Validierungsaufgaben" hinzugefügt .
Aliteralmind

Antworten:

212

Eine vollständige HTML-Analyse ist mit regulären Ausdrücken nicht möglich, da dies davon abhängt, ob das öffnende und das schließende Tag übereinstimmen, was mit regulären Ausdrücken nicht möglich ist.

Reguläre Ausdrücke können nur mit regulären Sprachen übereinstimmen , aber HTML ist eine kontextfreie Sprache und keine reguläre Sprache (Wie @StefanPochmann betonte, sind reguläre Sprachen auch kontextfrei, sodass kontextfrei nicht unbedingt nicht regulär bedeutet). Das einzige, was Sie mit regulären Ausdrücken in HTML tun können, sind Heuristiken, aber das funktioniert nicht unter allen Bedingungen. Es sollte möglich sein, eine HTML-Datei zu präsentieren, die von einem regulären Ausdruck falsch abgeglichen wird.

Johannes Weiss
quelle
26
Beste Antwort bisher. Wenn es nur mit regulären Grammatiken übereinstimmen kann, benötigen wir einen unendlich großen regulären Ausdruck, um eine kontextfreie Grammatik wie HTML zu analysieren. Ich liebe es, wenn diese Dinge klare theoretische Antworten haben.
Ntownsend
2
Ich nahm an, wir diskutierten reguläre Ausdrücke vom Typ Perl, bei denen es sich nicht um reguläre Ausdrücke handelt.
Hank Gay
5
Tatsächlich können reguläre .Net-Ausdrücke das Öffnen und Schließen von Tags in gewissem Maße mithilfe von Ausgleichsgruppen und einem sorgfältig gestalteten Ausdruck abgleichen. Enthalten , alle noch verrückt natürlich in einem regulären Ausdruck davon ist, wäre es wie der große Code aussieht Chtulhu und würde wahrscheinlich die realen als auch beschwören. Und am Ende wird es immer noch nicht in allen Fällen funktionieren. Sie sagen, wenn Sie einen regulären Ausdruck schreiben, der jeden HTML-Code korrekt analysieren kann, wird das Universum auf sich selbst zusammenbrechen.
Alex Paven
5
Einige Regex-Bibliotheken können rekursive reguläre Ausdrücke ausführen (was sie effektiv zu nicht regulären Ausdrücken macht :)
Ondra Žižka
43
-1 Diese Antwort zieht die richtige Schlussfolgerung ("Es ist eine schlechte Idee, HTML mit Regex zu analysieren") aus falschen Argumenten ("Weil HTML keine reguläre Sprache ist"). Das, was die meisten Leute heutzutage meinen, wenn sie "Regex" (PCRE) sagen, ist nicht nur in der Lage, kontextfreie Grammatiken zu analysieren (das ist eigentlich trivial), sondern auch kontextsensitive Grammatiken (siehe stackoverflow.com/questions/7434272/). … ).
NikiC
35

Für schnelles und schmutziges Regexp ist das in Ordnung. Das Grundlegende zu wissen ist jedoch, dass es unmöglich ist , einen regulären Ausdruck zu erstellen, der HTML korrekt analysiert.

Der Grund dafür ist, dass reguläre Ausdrücke keine arbitarisch verschachtelten Ausdrücke verarbeiten können. Siehe Können reguläre Ausdrücke verwendet werden, um verschachtelte Muster abzugleichen?

kmkaplan
quelle
1
Einige Regex-Bibliotheken können rekursive reguläre Ausdrücke ausführen (was sie effektiv zu nicht regulären Ausdrücken macht :)
Ondra Žižka
23

(Von http://htmlparsing.com/regexes )

Angenommen, Sie haben eine HTML-Datei, in der Sie versuchen, URLs aus <img> -Tags zu extrahieren.

<img src="http://example.com/whatever.jpg">

Sie schreiben also einen regulären Ausdruck in Perl:

if ( $html =~ /<img src="(.+)"/ ) {
    $url = $1;
}

In diesem Fall $urlwird in der Tat enthalten http://example.com/whatever.jpg. Aber was passiert, wenn Sie HTML wie folgt erhalten:

<img src='http://example.com/whatever.jpg'>

oder

<img src=http://example.com/whatever.jpg>

oder

<img border=0 src="http://example.com/whatever.jpg">

oder

<img
    src="http://example.com/whatever.jpg">

oder Sie bekommen falsch positive Ergebnisse von

<!-- // commented out
<img src="http://example.com/outdated.png">
-->

Es sieht so einfach aus, und es mag für eine einzelne, unveränderliche Datei einfach sein, aber für alles, was Sie mit beliebigen HTML-Daten tun werden, sind reguläre Ausdrücke nur ein Rezept für zukünftigen Herzschmerz.

Andy Lester
quelle
4
Dies scheint die eigentliche Antwort zu sein - während es wahrscheinlich möglich ist, beliebigen HTML-Code mit Regex zu analysieren, da heutige Regexes mehr als nur endliche Automaten sind. Um willkürliches HTML und nicht nur eine konkrete Seite zu analysieren, müssen Sie einen HTML-Parser in Regexp neu implementieren und Regexes werden sicherlich 1000-mal unlesbar.
Smit Johnth
1
Hey Andy, ich habe mir die Zeit genommen, einen Ausdruck zu finden, der Ihre erwähnten Fälle unterstützt. stackoverflow.com/a/40095824/1204332 Lassen Sie mich wissen, was Sie denken! :)
Ivan Chaer
2
Die Argumentation in dieser Antwort ist weit veraltet und gilt heute noch weniger als ursprünglich (was meiner Meinung nach nicht der Fall war ). (Zitat OP: "Wenn Sie nur etwas Einfaches, Schnelles oder Schmutziges tun ...".)
Gr.
16

Zwei schnelle Gründe:

  • Es ist schwierig, einen regulären Ausdruck zu schreiben, der böswilligen Eingaben standhält. viel schwieriger als mit einem vorgefertigten Werkzeug
  • Es ist schwierig, einen regulären Ausdruck zu schreiben, der mit dem lächerlichen Markup funktioniert, an dem Sie unweigerlich festhalten werden. viel schwieriger als mit einem vorgefertigten Werkzeug

In Bezug auf die Eignung von Regexen für das Parsen im Allgemeinen: Sie sind nicht geeignet. Haben Sie jemals die Art von Regexes gesehen, die Sie benötigen würden, um die meisten Sprachen zu analysieren?

Hank Gay
quelle
2
Beeindruckend? Ein Downvote nach 2+ Jahren? Für den Fall, dass sich jemand wunderte, sagte ich nicht "Weil es theoretisch unmöglich ist", weil die Frage eindeutig nach "schnell und schmutzig" und nicht nach "richtig" gestellt wurde. Das OP las eindeutig bereits Antworten, die das theoretisch unmögliche Gebiet abdeckten und dennoch nicht zufrieden waren.
Hank Gay
1
Habe nach 5+ Jahren eine positive Bewertung. :) Ich bin nicht qualifiziert zu sagen, warum Sie die Ablehnung erhalten haben, aber ich persönlich hätte mir lieber einige Beispiele oder Erklärungen als die abschließende rhetorische Frage gewünscht.
Adam Jensen
3
Im Wesentlichen ist jede schnelle und schmutzige HTML-Analyse, die in Versandprodukten oder internen Tools durchgeführt wird, eine klaffende Sicherheitslücke oder ein Fehler, der darauf wartet, passiert zu werden. Es muss mit Begeisterung entmutigt werden. Wenn man einen regulären Ausdruck verwenden kann, kann man einen richtigen HTML-Parser verwenden.
Stellen Sie Monica
16

In Bezug auf das Parsen können reguläre Ausdrücke in der Phase der "lexikalischen Analyse" (Lexer) nützlich sein, in der die Eingabe in Token unterteilt wird. In der eigentlichen Phase "Erstellen eines Analysebaums" ist dies weniger nützlich.

Für einen HTML-Parser würde ich erwarten, dass er nur wohlgeformtes HTML akzeptiert, und dies erfordert Funktionen, die außerhalb der Möglichkeiten eines regulären Ausdrucks liegen (sie können nicht "zählen" und sicherstellen, dass eine bestimmte Anzahl von Eröffnungselementen durch dieselbe Anzahl ausgeglichen wird von schließenden Elementen).

Vatine
quelle
8

Da es viele Möglichkeiten gibt, HTML zu "vermasseln", die Browser auf ziemlich liberale Weise behandeln, wäre es jedoch ziemlich aufwändig, das liberale Verhalten des Browsers zu reproduzieren, um alle Fälle mit regulären Ausdrücken abzudecken, sodass Ihre Regex bei bestimmten Sondervorgängen unvermeidlich fehlschlägt Fälle, und das würde möglicherweise ernsthafte Sicherheitslücken in Ihrem System führen.

Tamas Czinege
quelle
1
Sehr wahr, der Großteil des HTML-Codes scheint schrecklich zu sein. Ich verstehe nicht, wie ein fehlerhafter regulärer Ausdruck zu ernsthaften Sicherheitslücken führen kann. Kannst du ein Beispiel geben?
Ntownsend
4
ntownsend: Zum Beispiel denken Sie, Sie haben alle Skript-Tags aus dem HTML-Code entfernt, aber Ihre Regex-Fehler decken einen Sonderfall ab (der beispielsweise nur in IE6 funktioniert): Boom, Sie haben eine XSS-Sicherheitsanfälligkeit!
Tamas Czinege
1
Dies war ein streng hypothetisches Beispiel, da die meisten Beispiele aus der realen Welt zu kompliziert sind, um in diese Kommentare zu passen, aber Sie könnten einige finden, indem Sie schnell zu diesem Thema googeln.
Tamas Czinege
3
+1 für die Erwähnung des Sicherheitswinkels. Wenn Sie mit dem gesamten Internet verbunden sind, können Sie es sich nicht leisten, hackigen Code zu schreiben, der die meiste Zeit funktioniert.
j_random_hacker
7

Das Problem ist, dass die meisten Benutzer, die eine Frage stellen, die mit HTML und Regex zu tun hat, dies tun, weil sie keinen eigenen Regex finden, der funktioniert. Dann muss man sich überlegen, ob bei Verwendung eines DOM- oder SAX-Parsers oder ähnlichem alles einfacher wäre. Sie sind für die Arbeit mit XML-ähnlichen Dokumentstrukturen optimiert und konstruiert.

Sicher, es gibt Probleme, die mit regulären Ausdrücken leicht gelöst werden können. Aber der Schwerpunkt liegt auf leicht .

Wenn Sie nur alle URLs finden möchten, die so aussehen, als http://.../wären Sie mit regulären Ausdrücken einverstanden. Wenn Sie jedoch alle URLs finden möchten, die sich in einem a-Element mit der Klasse 'mylink' befinden, verwenden Sie wahrscheinlich besser einen geeigneten Parser.

Okoman
quelle
6

Reguläre Ausdrücke wurden nicht für die Verarbeitung einer verschachtelten Tag-Struktur entwickelt, und es ist bestenfalls kompliziert (im schlimmsten Fall unmöglich), alle möglichen Randfälle zu behandeln, die Sie mit echtem HTML erhalten.

Peter Boughton
quelle
6

Ich glaube, dass die Antwort in der Berechnungstheorie liegt. Damit eine Sprache mit Regex analysiert werden kann, muss sie per Definition "normal" sein ( Link ). HTML ist keine reguläre Sprache, da es eine Reihe von Kriterien für eine reguläre Sprache nicht erfüllt (viel zu tun mit den vielen Verschachtelungsebenen, die HTML-Code innewohnt). Wenn Sie sich für die Berechnungstheorie interessieren, würde ich dieses Buch empfehlen .

Tagger
quelle
1
Ich habe das Buch tatsächlich gelesen. Mir ist einfach nicht in den Sinn gekommen, dass HTML eine kontextfreie Sprache ist.
Ntownsend
4

Dieser Ausdruck ruft Attribute aus HTML-Elementen ab. Es unterstützt:

  • nicht zitierte / zitierte Attribute,
  • einfache / doppelte Anführungszeichen,
  • entkommene Anführungszeichen in Attributen,
  • Leerzeichen um Gleichheitszeichen,
  • beliebig viele Attribute,
  • Nur nach Attributen in Tags suchen.
  • Escape-Kommentare und
  • Verwalten Sie verschiedene Anführungszeichen innerhalb eines Attributwerts.

(?:\<\!\-\-(?:(?!\-\-\>)\r\n?|\n|.)*?-\-\>)|(?:<(\S+)\s+(?=.*>)|(?<=[=\s])\G)(?:((?:(?!\s|=).)*)\s*?=\s*?[\"']?((?:(?<=\")(?:(?<=\\)\"|[^\"])*|(?<=')(?:(?<=\\)'|[^'])*)|(?:(?!\"|')(?:(?!\/>|>|\s).)+))[\"']?\s*)

Schau es dir an . Es funktioniert besser mit den "gisx" -Flaggen als in der Demo.

Ivan Chaer
quelle
1
Das ist sehr interessant. Nicht lesbar, wahrscheinlich schwer zu debuggen, aber dennoch: Beeindruckende Arbeit!
Eric Duminil
Dies setzt immer noch vage voraus, dass der HTML-Code wohlgeformt ist. Ohne Kontextabgleich werden scheinbare URLs in Kontexten abgeglichen, in denen Sie sie normalerweise nicht abgleichen möchten, wie in einem Teil des JavaScript-Codes in einem <script>Tag.
Tripleee
4

HTML / XML ist in Markup und Inhalt unterteilt. Regex ist nur nützlich, wenn Sie eine lexikalische Tag-Analyse durchführen. Ich denke, Sie könnten den Inhalt ableiten. Es wäre eine gute Wahl für einen SAX-Parser. Tags und Inhalte können an eine benutzerdefinierte Funktion gesendet werden, mit der das Verschachteln / Schließen von Elementen verfolgt werden kann.

Das Parsen der Tags kann mit Regex erfolgen und zum Entfernen von Tags aus einem Dokument verwendet werden.

In jahrelangen Tests habe ich das Geheimnis gefunden, wie Browser gut und schlecht geformte Tags analysieren.

Die normalen Elemente werden mit dieser Form analysiert:

Der Kern dieser Tags verwendet diesen regulären Ausdruck

 (?:
      " [\S\s]*? " 
   |  ' [\S\s]*? ' 
   |  [^>]? 
 )+

Sie werden dies [^>]?als eine der Alternativen bemerken . Dies entspricht unausgeglichenen Anführungszeichen von schlecht geformten Tags.

Es ist auch die Wurzel aller Übel für reguläre Ausdrücke. Die Art und Weise, wie es verwendet wird, löst einen Bump-Along aus, um den gierigen, mit Must-Match quantifizierten Container zu befriedigen.

Bei passiver Verwendung gibt es kein Problem. Wenn Sie jedoch eine Übereinstimmung erzwingen , indem Sie sie mit einem gewünschten Attribut / Wert-Paar durchsetzen und keinen ausreichenden Schutz vor Rückverfolgung bieten, ist dies ein außer Kontrolle geratener Albtraum.

Dies ist die allgemeine Form für einfache alte Tags. Beachten Sie die [\w:]Darstellung des Tag-Namens? In Wirklichkeit sind die legalen Zeichen, die den Tag-Namen darstellen, eine unglaubliche Liste von Unicode-Zeichen.

 <     
 (?:
      [\w:]+ 
      \s+ 
      (?:
           " [\S\s]*? " 
        |  ' [\S\s]*? ' 
        |  [^>]? 
      )+
      \s* /?
 )
 >

Im weiteren Verlauf sehen wir auch, dass Sie einfach nicht nach einem bestimmten Tag suchen können, ohne ALLE Tags zu analysieren . Ich meine, Sie könnten, aber es müsste eine Kombination von Verben wie (* SKIP) (* FAIL) verwendet werden, aber dennoch müssen alle Tags analysiert werden.

Der Grund dafür ist, dass die Tag-Syntax möglicherweise in anderen Tags usw. verborgen ist.

Um alle Tags passiv zu analysieren, wird ein regulärer Ausdruck wie der folgende benötigt. Dieser besondere passt auch zu unsichtbaren Inhalten .

Wenn neues HTML oder XML oder andere neue Konstrukte entwickeln, fügen Sie es einfach als eine der Alternativen hinzu.


Hinweis zur Webseite - Ich habe noch nie eine Webseite (oder xhtml / xml) gesehen, mit der dies
Probleme hatte. Wenn Sie einen finden, lassen Sie es mich wissen.

Leistungshinweis - Es geht schnell. Dies ist der schnellste Tag-Parser, den ich gesehen habe
(es kann schneller sein, wer weiß).
Ich habe mehrere spezifische Versionen. Es eignet sich auch hervorragend als Schaber
(wenn Sie ein praktischer Typ sind).


Komplette rohe Regex

<(?:(?:(?:(script|style|object|embed|applet|noframes|noscript|noembed)(?:\s+(?>"[\S\s]*?"|'[\S\s]*?'|(?:(?!/>)[^>])?)+)?\s*>)[\S\s]*?</\1\s*(?=>))|(?:/?[\w:]+\s*/?)|(?:[\w:]+\s+(?:"[\S\s]*?"|'[\S\s]*?'|[^>]?)+\s*/?)|\?[\S\s]*?\?|(?:!(?:(?:DOCTYPE[\S\s]*?)|(?:\[CDATA\[[\S\s]*?\]\])|(?:--[\S\s]*?--)|(?:ATTLIST[\S\s]*?)|(?:ENTITY[\S\s]*?)|(?:ELEMENT[\S\s]*?))))>

Formatierter Look

 <
 (?:
      (?:
           (?:
                # Invisible content; end tag req'd
                (                             # (1 start)
                     script
                  |  style
                  |  object
                  |  embed
                  |  applet
                  |  noframes
                  |  noscript
                  |  noembed 
                )                             # (1 end)
                (?:
                     \s+ 
                     (?>
                          " [\S\s]*? "
                       |  ' [\S\s]*? '
                       |  (?:
                               (?! /> )
                               [^>] 
                          )?
                     )+
                )?
                \s* >
           )

           [\S\s]*? </ \1 \s* 
           (?= > )
      )

   |  (?: /? [\w:]+ \s* /? )
   |  (?:
           [\w:]+ 
           \s+ 
           (?:
                " [\S\s]*? " 
             |  ' [\S\s]*? ' 
             |  [^>]? 
           )+
           \s* /?
      )
   |  \? [\S\s]*? \?
   |  (?:
           !
           (?:
                (?: DOCTYPE [\S\s]*? )
             |  (?: \[CDATA\[ [\S\s]*? \]\] )
             |  (?: -- [\S\s]*? -- )
             |  (?: ATTLIST [\S\s]*? )
             |  (?: ENTITY [\S\s]*? )
             |  (?: ELEMENT [\S\s]*? )
           )
      )
 )
 >
Tripleee
quelle
3

"Es kommt aber darauf an". Es ist wahr, dass reguläre Ausdrücke HTML aus allen hier angegebenen Gründen nicht mit wahrer Genauigkeit analysieren können und können. Wenn die Konsequenzen eines Fehlers (z. B. das Nichthandhaben verschachtelter Tags) jedoch gering sind und Regexes in Ihrer Umgebung sehr praktisch sind (z. B. wenn Sie Perl hacken), fahren Sie fort.

Angenommen, Sie analysieren Webseiten, die auf Ihre Website verweisen - vielleicht haben Sie sie mit einer Google-Linksuche gefunden - und möchten einen schnellen Überblick über den Kontext Ihres Links erhalten. Sie versuchen, einen kleinen Bericht zu erstellen, der Sie möglicherweise auf das Verknüpfen von Spam aufmerksam macht.

In diesem Fall ist es keine große Sache, einige der Dokumente falsch zu analysieren. Niemand außer Ihnen wird die Fehler sehen, und wenn Sie sehr viel Glück haben, gibt es nur wenige, die Sie individuell nachverfolgen können.

Ich denke, ich sage, es ist ein Kompromiss. Manchmal ist die Implementierung oder Verwendung eines korrekten Parsers - so einfach das auch sein mag - die Mühe nicht wert, wenn die Genauigkeit nicht kritisch ist.

Sei einfach vorsichtig mit deinen Annahmen. Ich kann mir einige Möglichkeiten vorstellen, wie die Regexp-Verknüpfung nach hinten losgehen kann, wenn Sie versuchen, etwas zu analysieren, das beispielsweise öffentlich gezeigt wird.

Katzenfutter
quelle
3

Es gibt definitiv Fälle, in denen die Verwendung eines regulären Ausdrucks zum Parsen einiger Informationen aus HTML der richtige Weg ist - dies hängt stark von der jeweiligen Situation ab.

Der obige Konsens ist, dass es im Allgemeinen eine schlechte Idee ist. Wenn die HTML-Struktur jedoch bekannt ist (und sich wahrscheinlich nicht ändert), ist dies immer noch ein gültiger Ansatz.

Jason
quelle
3

Beachten Sie, dass HTML selbst zwar nicht regelmäßig ist, Teile einer Seite, die Sie sich ansehen, jedoch möglicherweise regelmäßig sind.

Beispielsweise ist es ein Fehler <form>, wenn Tags verschachtelt werden. Wenn die Webseite korrekt funktioniert, ist <form>es völlig sinnvoll , einen regulären Ausdruck zu verwenden, um eine zu erfassen.

Ich habe kürzlich Web-Scraping nur mit Selen und regulären Ausdrücken durchgeführt. Ich habe mit ihm weg , weil die Daten , die ich in einem setzen wollte <form>, und legten in einem einfachen Tabellenformat (so ich zählen konnte sogar <table>, <tr>und <td>nicht verschachtelt zu sein - das ist eigentlich sehr ungewöhnlich ist). In gewissem Maße waren reguläre Ausdrücke sogar fast notwendig, da ein Teil der Struktur, auf die ich zugreifen musste, durch Kommentare begrenzt war. (Schöne Suppe kann Ihnen Kommentare geben, aber es wäre schwierig gewesen, mit Schöne Suppe zu greifen <!-- BEGIN -->und zu <!-- END -->blockieren.)

Wenn ich mich jedoch um verschachtelte Tabellen kümmern müsste, hätte mein Ansatz einfach nicht funktioniert! Ich hätte auf Beautiful Soup zurückgreifen müssen. Selbst dann können Sie jedoch manchmal einen regulären Ausdruck verwenden, um den benötigten Block zu erfassen und von dort aus einen Drilldown durchzuführen.

Alpheus
quelle
2

Tatsächlich ist HTML-Parsing mit Regex in PHP durchaus möglich. Sie müssen nur die gesamte Zeichenfolge rückwärts analysieren strrpos, um <den regulären Ausdruck von dort aus zu finden und zu wiederholen. Verwenden Sie dabei jedes Mal ungreedy-Bezeichner, um über verschachtelte Tags hinwegzukommen. Nicht schick und furchtbar langsam bei großen Dingen, aber ich habe es für meinen persönlichen Vorlageneditor für meine Website verwendet. Ich habe nicht wirklich HTML analysiert, sondern ein paar benutzerdefinierte Tags, die ich zum Abfragen von Datenbankeinträgen erstellt habe, um Datentabellen anzuzeigen (mein <#if()>Tag könnte auf diese Weise spezielle Einträge hervorheben). Ich war nicht bereit, hier und da einen XML-Parser für nur ein paar selbst erstellte Tags (mit sehr Nicht-XML-Daten) zu verwenden.

Obwohl diese Frage erheblich tot ist, wird sie dennoch in einer Google-Suche angezeigt. Ich las es und dachte, "Herausforderung angenommen" und beendete die Korrektur meines einfachen Codes, ohne alles ersetzen zu müssen. Beschlossen, jedem, der nach einem ähnlichen Grund sucht, eine andere Meinung zu geben. Auch die letzte Antwort wurde vor 4 Stunden gepostet, daher ist dies immer noch ein heißes Thema.

Deji
quelle
2
-1 für den Vorschlag einer SCHRECKLICHEN Idee. Haben Sie Leerzeichen zwischen dem Tag und der schließenden Klammer berücksichtigt? (ZB <tag >) Haben Sie über auskommentierte schließende Tags nachgedacht? (ZB <tag> <!-- </tag> -->) Haben Sie über CDATA nachgedacht? Haben Sie inkonsistente Fall-Tags in Betracht gezogen? (ZB <Tag> </tAG>) finden Sie diese auch?
Montag,
1
Im speziellen Fall Ihrer wenigen benutzerdefinierten Tags funktionieren reguläre Ausdrücke gut. Es ist also nicht so, dass Ihre Verwendung in Ihrem speziellen Fall ein Fehler war . Das ist jedoch kein HTML, und zu sagen, dass "HTML-Parsing mit Regex in PHP durchaus möglich ist", ist einfach falsch und eine SCHRECKLICHE Idee. Die Inkonsistenzen von echtem HTML (und es gibt weit mehr als die wenigen, die ich aufgelistet habe) sind der Grund, warum Sie echtes HTML niemals mit regulären Ausdrücken analysieren sollten. Siehe auch alle anderen Antworten auf diese Frage sowie die, auf die ich in meinem anderen Kommentar oben verwiesen habe.
rmunn
2
PHP ist eine turing-vollständige Sprache, daher ist es überhaupt nicht falsch. Alles, was rechnerisch möglich ist, ist möglich, einschließlich des Parsens von HTML. Leerzeichen in Tags waren NIE ein Problem und ich habe es seitdem angepasst, um Tag-Elemente der Reihe nach aufzulisten. Meine Verwendung korrigierte Tags mit inkonsistentem Gehäuse automatisch, entfernte kommentierte Inhalte in der ersten Phase und nach einigen späteren Hinzufügungen können alle Arten von Tags einfach hinzugefügt werden (obwohl nach meiner Wahl zwischen Groß- und Kleinschreibung unterschieden wird). Und ich bin mir ziemlich sicher, dass CDATA tatsächlich ein XML-Element ist, kein HTML-Element.
Deji
2
Meine alte Methode (die ich hier beschrieben habe) war ziemlich ineffizient und ich habe kürzlich begonnen, viele der Inhaltseditoren neu zu schreiben. Wenn es darum geht, diese Dinge zu tun, ist die Möglichkeit nicht das Problem; Der beste Weg ist immer das Hauptanliegen. Die eigentliche Antwort lautet: "In PHP gibt es keine EINFACHE Möglichkeit, dies zu tun." Niemand sagt, dass es in PHP keine Möglichkeit gibt oder dass es eine schreckliche Idee ist, aber dass es mit Regex unmöglich ist, was ich ehrlich gesagt nie versucht habe, aber der einzige große Fehler in meiner Antwort ist, dass ich angenommen habe, dass sich die Frage auf Regex bezieht im Kontext von PHP, was nicht unbedingt der Fall ist.
Deji
2

Auch dafür habe ich mich an einer Regex versucht. Dies ist vor allem nützlich, um Inhaltsblöcke zu finden, die mit dem nächsten HTML-Tag gepaart sind, und es wird nicht nach passenden Close-Tags gesucht, aber es werden Close-Tags gefunden. Rollen Sie einen Stapel in Ihrer eigenen Sprache, um diese zu überprüfen.

Mit 'sx'-Optionen verwenden. 'g' auch, wenn Sie Glück haben:

(?P<content>.*?)                # Content up to next tag
(?P<markup>                     # Entire tag
  <!\[CDATA\[(?P<cdata>.+?)]]>| # <![CDATA[ ... ]]>
  <!--(?P<comment>.+?)-->|      # <!-- Comment -->
  </\s*(?P<close_tag>\w+)\s*>|  # </tag>
  <(?P<tag>\w+)                 # <tag ...
    (?P<attributes>
      (?P<attribute>\s+
# <snip>: Use this part to get the attributes out of 'attributes' group.
        (?P<attribute_name>\w+)
        (?:\s*=\s*
          (?P<attribute_value>
            [\w:/.\-]+|         # Unquoted
            (?=(?P<_v>          # Quoted
              (?P<_q>['\"]).*?(?<!\\)(?P=_q)))
            (?P=_v)
          ))?
# </snip>
      )*
    )\s*
  (?P<is_self_closing>/?)   # Self-closing indicator
  >)                        # End of tag

Dieser ist für Python konzipiert (er funktioniert möglicherweise für andere Sprachen, hat ihn noch nicht ausprobiert, verwendet positive Lookaheads, negative Lookbehinds und benannte Rückreferenzen). Unterstützt:

  • Tag öffnen - <div ...>
  • Tag schließen - </div>
  • Kommentar - <!-- ... -->
  • CDATA - <![CDATA[ ... ]]>
  • Selbstschließender Tag - <div .../>
  • Optionale Attributwerte - <input checked>
  • Nicht zitierte / zitierte Attributwerte - <div style='...'>
  • Einfache / doppelte Anführungszeichen - <div style="...">
  • Escaped Quotes - <a title='John\'s Story'>
    (das ist kein wirklich gültiger HTML-Code, aber ich bin ein netter Kerl)
  • Leerzeichen um Gleichheitszeichen - <a href = '...'>
  • Benannte Aufnahmen für interessante Bits

Es ist auch ziemlich gut, keine fehlerhaften Tags auszulösen, beispielsweise wenn Sie ein <oder vergessen >.

Wenn Ihre Regex-Variante wiederholte benannte Captures unterstützt, sind Sie golden, Python rejedoch nicht (ich weiß, dass Regex dies tut, aber ich muss Vanille-Python verwenden). Folgendes erhalten Sie:

  • content- Der gesamte Inhalt bis zum nächsten Tag. Sie könnten das weglassen.
  • markup - Das gesamte Tag mit allem darin.
  • comment - Wenn es sich um einen Kommentar handelt, wird der Kommentarinhalt angezeigt.
  • cdata- Wenn es ein ist <![CDATA[...]]>, der CDATA-Inhalt.
  • close_tag- Wenn es sich um ein Close-Tag ( </div>) handelt, den Tag-Namen.
  • tag- Wenn es sich um ein offenes Tag ( <div>) handelt, der Tag-Name.
  • attributes- Alle Attribute innerhalb des Tags. Verwenden Sie diese Option, um alle Attribute abzurufen, wenn Sie keine wiederholten Gruppen erhalten.
  • attribute - Wiederholt jedes Attribut.
  • attribute_name - Wiederholt jeden Attributnamen.
  • attribute_value- Wiederholt jeden Attributwert. Dies schließt die Anführungszeichen ein, wenn es zitiert wurde.
  • is_self_closing- Dies ist, /wenn es sich um ein selbstschließendes Tag handelt, sonst nichts.
  • _qund _v- diese ignorieren; Sie werden intern für Rückreferenzen verwendet.

Wenn Ihre Regex-Engine keine wiederholten benannten Captures unterstützt, wird ein Abschnitt aufgerufen, in dem Sie jedes Attribut abrufen können. Führen Sie einfach , dass regex auf die attributesGruppe jeweils zu bekommen attribute, attribute_nameund attribute_valueaus ihm heraus.

Demo hier: https://regex101.com/r/mH8jSu/11

Hounshell
quelle
1

Reguläre Ausdrücke sind für eine solche Sprache wie HTML nicht leistungsfähig genug. Sicher, es gibt einige Beispiele, in denen Sie reguläre Ausdrücke verwenden können. Im Allgemeinen ist es jedoch nicht zum Parsen geeignet.

Gumbo
quelle
0

Weißt du ... es gibt eine Menge Mentalität von dir, die es NICHT kann und ich denke, dass jeder auf beiden Seiten des Zauns richtig und falsch ist. Sie KÖNNEN es tun, aber es erfordert etwas mehr Verarbeitung, als nur einen regulären Ausdruck dagegen auszuführen. Nehmen Sie dies (ich habe es innerhalb einer Stunde geschrieben) als Beispiel. Es wird davon ausgegangen, dass der HTML-Code vollständig gültig ist. Abhängig von der Sprache, in der Sie den oben genannten regulären Ausdruck anwenden, können Sie den HTML-Code jedoch korrigieren, um sicherzustellen, dass er erfolgreich ist. Entfernen Sie beispielsweise schließende Tags, die nicht vorhanden sein sollen: </img>Zum Beispiel. Fügen Sie dann den schließenden einzelnen HTML-Schrägstrich zu Elementen hinzu, denen diese fehlen usw.

Ich würde dies im Zusammenhang mit dem Schreiben einer Bibliothek verwenden, mit der ich beispielsweise HTML-Elemente abrufen kann, die denen von JavaScript [x].getElementsByTagName()ähneln. Ich würde einfach die Funktionalität, die ich im Abschnitt DEFINE der Regex geschrieben habe, zusammenfügen und sie verwenden, um nacheinander in einen Baum von Elementen zu treten.

Wird dies die endgültige 100% ige Antwort für die Validierung von HTML sein? Nein, aber es ist ein Anfang und mit etwas mehr Arbeit kann es getan werden. Der Versuch, dies innerhalb einer Regex-Ausführung zu tun, ist jedoch weder praktisch noch effizient.

Erutan409
quelle