Warum ist es nicht möglich mit regex zu Parsen von HTML - /XML: eine formale Erklärung in einfachen Worten
Es gibt keinen Tag an SO, der vergeht, ohne eine Frage zu Parsen von (X)HTML-oder XML mit regulären Ausdrücken gefragt.
Es ist zwar relativ einfach zu kommen mit Beispiele, wie der nicht-Lebensfähigkeit von regexes für diese Aufgabe oder mit einem Sammlung von Ausdrücken repräsentieren das Konzept, konnte ich noch nicht finden, SO dass eine formale Erklärung, warum das nicht möglich ist, erfolgt in juristischer Hinsicht.
Nur formale Erklärungen, die ich finden konnte bisher auf dieser Website sind wahrscheinlich sehr genau, aber auch ziemlich kryptisch zu der Autodidakt Programmierer:
dem Fehler hier ist, dass HTML eine Chomsky Typ-2 Grammatik (Kontext-frei
Grammatik) und RegEx ist eine Chomsky-Typ-3 Grammatik (reguläre Ausdrücke)
oder:
Reguläre Ausdrücke können nur reguläre Sprachen, aber HTML ist eine
Kontext-freie Sprache.
oder:
Einer endlichen Automaten (die den Daten zugrunde liegenden Struktur eine regelmäßige
Ausdruck) nicht den Speicher neben dem Staat ist es in, und wenn
Sie haben beliebig tief verschachteln, müssen Sie eine beliebig große
Automat, das kollidiert mit der Vorstellung eines endlichen Automaten.
oder:
Dem Pumping lemma für reguläre Sprachen ist der Grund, warum Sie nicht tun können
.
[Um fair zu sein: die Mehrheit der oben genannten Erklärung link zu wikipedia-Seiten, aber diese sind auch nicht viel einfacher zu verstehen als die Antworten selbst].
Also meine Frage ist: könnte jemand bitte eine übersetzung in juristischer Hinsicht von den formellen Erklärungen, die oben gegeben werden, warum ist es nicht möglich mit regex zum Parsen von (X)HTML/XML?
EDIT: Nach dem Lesen der ersten Antwort dachte ich, ich sollte klarstellen: ich bin auf der Suche nach einer "übersetzung", die auch briefely erklärt die Begriffe, die es versucht zu übersetzen: am Ende einer Antwort, sollte der Leser eine grobe Idee - zum Beispiel - von dem, was "reguläre Sprache" und "kontextfreie Grammatik" bedeuten...
Das ist wirklich nur für Sprachen, die missbrauchen den Begriff "regulärer Ausdruck. POSIX-ERE-ist regelmäßig rein.
also, nennen Sie POSIX einer "modernen Umsetzung" :P. Im ernst aber: ja, du hast Recht, diejenigen, die wirklich regelmäßige. Ich habe gesagt "... viele der modernen regex-Implementierungen ..." oder "... PCRE-regex-Implementierungen ...".
Ich habe eine harte Zeit ernst zu nehmen Programmiersprachen, die grundsätzlich den Missbrauch rigorose Sprache für den Willen des marketing selbst, um unwissende Programmierer...
es ist bedauerlich, dass die PCRE-Implementierungen sind so genannte "reguläre Ausdrücke", aber nicht, dass man die Sprache ernst nimmt es einen Schritt zu weit, IMO. Ich meine, sind Sie nicht unter Perl, Java, Python, Ruby, JavaScript, .NET, etc. nicht ernst, denn von diesem?
InformationsquelleAutor mac | 2011-07-19
Du musst angemeldet sein, um einen Kommentar abzugeben.
Konzentrieren Sie sich auf dieses:
Den definition der regulären Ausdrücke entspricht der Tatsache, dass ein test, ob ein string dem Muster entspricht, durchgeführt werden kann durch eine endliche Automaten (verschiedene Automaten für jedes Muster). Ein endlicher Automat hat kein Gedächtnis - keine Stapel, kein Haufen, keine unendlichen Band zu kritzeln auf. Es wird eine endliche Anzahl von inneren Zuständen, von denen jeder Lesen können eine Einheit von Eingaben aus der Zeichenkette, die geprüft werden, und nutzen, um zu entscheiden, welcher Staat sich zu bewegen weiter. Als Besondere Fälle, hat es zwei Staaten Kündigung: "ja, das abgestimmt", und "Nein, das hat nicht mit".
HTML, auf der anderen Seite, hat die Strukturen können beliebig tief verschachteln. Um zu bestimmen, ob eine HTML-Datei gültig ist oder nicht, müssen Sie überprüfen Sie, dass alle schließenden tags übereinstimmen, eine frühere Eröffnung-tag. Um es zu verstehen, müssen Sie wissen, welches element geschlossen wird. Ohne jede Möglichkeit zu "erinnern", was öffnen von tags, die Sie gesehen haben, keine chance.
Beachten Sie jedoch, dass die meisten "regex" - Bibliotheken erlauben mehr als nur die strenge definition von regulären Ausdrücken. Wenn Sie match-back-Referenzen, dann haben Sie schon über eine reguläre Sprache. Also der Grund, warum sollten Sie nicht verwenden, eine regex-Bibliothek, die auf HTML ist ein wenig komplexer als die einfache Tatsache, dass HTML nicht regelmäßig.
InformationsquelleAutor Steve Jessop
Die Tatsache, dass der HTML nicht darstellen, eine reguläre Sprache ist ein Roter Hering. Reguläre Ausdrücke und reguläre Sprachen Klang irgendwie ähnlich, aber nicht - Sie teilen die gleiche Herkunft, aber es gibt eine Bemerkenswerte Distanz zwischen der akademischen "reguläre Sprachen" und das aktuelle matching-power-Motoren. In der Tat, fast alle modernen regelmäßige Ausdruck-Motoren die Unterstützung von nicht-regulären Funktionen - ein einfaches Beispiel ist
(.*)\1
. die verwendet für rückreferenzierung zu entsprechen, eine wiederholte Folge von Zeichen, beispielsweise123123
oderbonbon
. Matching von rekursiven/symmetrische Strukturen machen diese noch mehr Spaß.Wikipedia setzt diese schön in einem Zitat von Larry Wall:
"Regulären Ausdruck können nur reguläre Sprachen", wie Sie sehen können, ist nichts anderes als eine allgemein angegeben Trugschluss.
So, warum dann nicht?
Einen guten Grund, nicht zu entsprechen, HTML mit regulären Ausdrücken ist, dass "nur weil Sie können bedeutet nicht, Sie sollten". Zwar kann möglich sein, - es gibt einfach bessere tools für den job. In Erwägung:
Sehr oft ist es unmöglich, einen Teil der Daten ohne Analyse als ganzes. Zum Beispiel, Sie könnten auf der Suche nach allen Titeln, und am Ende matching in einem Kommentar oder ein string-literal.
<h1>.*?</h1>
werden können, einen kühnen Versuch zu finden, die wichtigsten Titel, sondern es finden könnte:Oder auch:
Letzte Punkt ist der wichtigste:
Einen guten überblick über das Thema und ein wichtiger Kommentar auf beim mischen von Regex und HTML geeignet sein könnten, finden sich in Jeff Atwood ' s blog: Parsen Von Html Die Cthulhu-Weg.
Wann ist es besser, einen regulären Ausdruck zu verwenden, zu analysieren HTML?
In den meisten Fällen ist es besser, auf XPath auf die DOM-Struktur einer Bibliothek geben kann. Noch, gegen der landläufigen Meinung, es gibt wenige Fälle, in denen würde ich dringend empfehlen, mit einem regex und nicht eine parser-Bibliothek:
Einige dieser Bedingungen:
Vielen Dank. Eigentlich hatte ich ihm einige Gedanken. Ich weiß, ich habe Ihre Frage nicht beantworten, aber ich glaube nicht, dass die Frage grundsätzlich richtig - Sie bitten zu erklären, der falsche Grund... Sie haben eine gute Idee, obwohl, vielleicht die andere Frage ist mehr geeignet...
InformationsquelleAutor Kobi
Weil HTML kann eine unbegrenzte Verschachtelung von
<tags><inside><tags and="<things><that><look></like></tags>"></inside></each></other>
und regex kann nicht wirklich bewältigen, weil Sie nicht Folgen können, eine Geschichte von dem, was es ist, stieg hinab in die und aus der.Einfaches Konstrukt, das veranschaulicht die Schwierigkeit:
99,9% der generalisierten regex-basierte Extraktion Routinen werden nicht in der Lage, richtig geben Sie mir alles innen der
div
mit der IDfoo
, denn Sie können nicht sagen, der End-tag für das div aus der schließende tag für denbar
div. Das ist, weil Sie keine Möglichkeit haben, zu sagen: "okay, ich habe jetzt abgestiegen in die zweite von zwei divs, so dass die nächste div in der Nähe ich sehe, bringt mich zurück, und der eine nach dass ist eine enge-tag für das erste". Programmierer in der Regel reagieren durch die Entwicklung spezieller Fall regexes für die spezifische situation, die dann brechen, sobald mehr tags eingeführt werden, innerhalbfoo
werden und sind unsnarled auf enorme Kosten mit der Zeit und frustration. Dies ist, warum die Menschen wütend über die ganze Sache.Dies ist eine übersetzung aller von Ihnen in gewissem Sinne, die meisten rund "Reguläre Ausdrücke können nur reguläre Sprachen, aber HTML ist eine Kontext-freie Sprache" und die über endliche Automaten. Es ist wirklich alles der gleiche Grund.
Sorry, vielleicht war ich nicht klar in meiner Frage (Vorschläge zur Verbesserung sind herzlich willkommen!). Aber ich Suche nach einer Antwort, erklärt auch die "übersetzung". Ihre Antwort hat nicht zu klären, entweder die 'reguläre Sprache' noch 'Kontext-freie Sprache' - Konzepten...
Welche Begriffe wären ebenso technische wie der jargon selbst, und eine Ablenkung von der eigentlichen Bedeutung, dass alle, die Präzision der Sprache ist immer an, dass was ich gepostet.
<(\w+)(?:\s+\w+="[^"]*")*>(?R)*</\1>|[\w\s!']+
Spiele dein code-Beispiel.InformationsquelleAutor Ianus Chiaroscuro
Einer regulären Sprache ist eine Sprache, die angepasst werden kann durch eine finite-state-Maschine.
(Verständnis Endlicher Automaten, pushdown-Automaten und Turing-Maschinen ist grundsätzlich der Lehrplan des vierten Jahr college-CS Natürlich.)
Betrachten die folgende Maschine, die erkennt die Zeichenfolge "Hallo".
Dies ist eine einfache Maschine zu erkennen, eine reguläre Sprache; Jeder Ausdruck in der Klammer ist ein Staat, und jeder Pfeil ist ein übergang. Bau einer Maschine, wie dies ermöglicht es Ihnen zu testen, die Eingabe-string gegen einen regulären Sprache -- also einem regulären Ausdruck.
HTML erfordert, dass Sie mehr wissen als nur das, was Zustand Sie sich befinden-es erfordert eine Geschichte von dem, was Sie gesehen haben, entsprechen Verschachtelung der Tags. Dies können Sie erreichen, wenn Sie einen Stapel in die Maschine, aber dann ist es nicht mehr "regulär". Dies wird als Push-down-Maschine und erkennt eine Grammatik.
Ich habe aktualisiert es. Ich weiß nicht, dass es allzu schwer zu verstehen, nur um zu erklären, in einen stack-overflow-post.
InformationsquelleAutor Sean McMillan
Ein regulärer Ausdruck ist eine Maschine mit einem endlichen (und in der Regel eher kleine) Anzahl von diskreten Zuständen.
Analysieren, XML, C oder einer anderen Sprache mit beliebiger Verschachtelung von sprachlichen Elementen, die Sie benötigen, zu erinnern, wie tief Sie sind. Das heißt, Sie müssen in der Lage sein zu zählen Klammern/Klammern/tags.
Können Sie nicht rechnen mit endlichen Speicher. Es kann mehr Klammer-Ebenen haben, als Sie Staaten! Sie könnten in der Lage zu analysieren, eine Teilmenge der Sprache ist, dass die Beschränkung der Anzahl der schachtelungsebenen, aber es wäre sehr mühsam.
InformationsquelleAutor n.m.
Eine Grammatik ist eine formale definition, wo Worte gehen kann. Zum Beispiel, die Adjektive preceed Substantive
in English grammar
ab, sondern Folgen Sie Substantiveen la gramática española
.Kontext-frei bedeutet, dass die grammer universell in allen Kontexten. Kontextsensitiv bedeutet, es gibt zusätzliche Regeln, die in bestimmten Kontexten.
In C#, zum Beispiel
using
bedeutet etwas anderes inusing System;
an der Spitze von Dateien, alsusing (var sw = new StringWriter (...))
. Eine relevantere Beispiel ist der folgende code in code:Aber Kontext-frei bedeutet nicht regelmäßig. Die Sprache abgestimmt paranthesis ist kontextfrei, aber nicht regulär.
Was sollte Hinzugefügt werden, dass reguläre Ausdrücke (es sei denn, Sie fügen Sie solche Erweiterungen wie in Perl) sind äquivalent zu regular grammars, das heißt, Sie kann nicht beschrieben werden beliebig tief geschachtelte Strukturen, wie willkürlich tief ausgewogene Klammern oder HTML-element öffnen und schließen-tags.
InformationsquelleAutor agent-j
Es ist ein weiterer praktischer Grund für die nicht-Verwendung von regulären Ausdrücken zum Parsen von XML und HTML, hat nichts zu tun mit der informatik-Theorie: der reguläre Ausdruck wird entweder schrecklich kompliziert oder es wird falsch sein.
Zum Beispiel, es ist alles sehr gut schreiben Sie einen regulären Ausdruck,
Aber, wenn dein code richtig ist, dann:
Muss es zulassen, Leerraum nach dem Elementnamen im start-und end-tag
Wenn das Dokument in einem namespace, dann sollte es erlauben, beliebigen namespace-Präfix verwendet werden
Sollte es wohl auch zulassen und ignorieren alle unbekannten Attribute, die in der start-tag (abhängig von der Semantik des jeweiligen Vokabular)
Kann es brauchen, zu ermöglichen Leerzeichen vor und nach dem dezimalen Wert (wieder, je nach den detaillierten Vorschriften der jeweiligen XML-Vokabular).
Sollte es nicht mit etwas, das aussieht wie ein element, aber ist eigentlich in einem Kommentar oder CDATA-Abschnitt (dies wird besonders wichtig, wenn es gibt eine Möglichkeit, schädliche Daten versucht zu täuschen Ihre parser).
Kann es brauchen, um Diagnose, wenn die Eingabe ungültig ist.
Natürlich einige dieser hängt von der Qualität standards, die Sie anwenden. Wir sehen eine Menge Probleme auf StackOverflow, die mit Menschen mit generieren von XML-Daten in einer bestimmten Weise (zum Beispiel keine Leerzeichen in den tags), weil es gelesen wird, von einer Anwendung, die es erfordert, werden auf eine bestimmte Weise geschrieben. Wenn Ihr code hat jede Art von Langlebigkeit, dann ist es wichtig, dass Sie sollten in der Lage sein, eingehende XML-geschrieben in einer Weise, die der XML-standard erlaubt, und nicht nur die sample-input-Dokuments, die Sie testen Ihren code auf.
InformationsquelleAutor Michael Kay
In einem rein theoretischen Sinn, es ist unmöglich, reguläre Ausdrücke zum Parsen von XML. Sie sind definiert in einer Weise, die Ihnen nicht die Erinnerung an alle früheren Zustand, so dass die korrekte Abstimmung von einem beliebigen tag, und Sie dringen kann zu einer beliebigen Tiefe der Schachtelung, da die Verschachtelung müssten gebaut werden, die in dem regulären Ausdruck.
Modernen regex-Parser, allerdings sind gebaut nach Ihrer Nützlichkeit für den Entwickler eher als die Einhaltung einer genauen definition. Als solche haben wir Dinge wie back-Referenzen und Rekursion, das wissen von den vorherigen Zuständen. Mit diesen ist es bemerkenswert einfach zu erstellen eines regex, erkunden, überprüfen oder analysieren von XML.
Denken Sie zum Beispiel an,
Diese finden das nächste richtig formatiertes XML-tag oder Kommentar, und es wird nur finden, wenn es den gesamten Inhalt korrekt geformt sind. (Dieser Ausdruck wurde getestet mit Notepad++, die verwendet Boost C++'s regex-Bibliothek, die sehr nahe PCRE.)
Hier ist, wie es funktioniert:
/>
, womit sich der tag, oder es wird am Ende mit einem>
, in welchem Fall es wird weiter durch die Untersuchung der tag-Inhalt.<
, an welcher Stelle es recurse zurück an den Anfang des Ausdrucks, die es ermöglicht, befassen sich mit entweder einen Kommentar oder einen neuen tag.<
, die es nicht analysieren kann. Andernfalls passen wird, natürlich, weil es um den Prozess zu starten über. Ansonsten, die<
ist vermutlich der Anfang des schließenden Tags für diese iteration. Mit der back-Referenz innerhalb einem schließenden tag<\/\1>
es wird mit dem öffnenden tag für die aktuelle iteration (Tiefe). Es gibt nur eine capturing group, also dieser Spiel ist ein einfache Sache. Dies macht Sie unabhängig von den Namen der tags verwendet, obwohl Sie könnte ändern Sie die Aufnahme-Gruppe zu erfassen, nur bestimmte tags, wenn Sie Sie benötigen.Diesem Beispiel löst die Probleme im Umgang mit whitespace oder die Identifikation von relevanten Inhalten durch die Verwendung von Zeichen-Gruppen, die nur negieren
<
oder>
oder, im Falle der Kommentare, durch die Verwendung[\S\s]
, die passt auf alles, einschließlich Wagenrücklauf und neue Linien, auch im single-line Modus fortsetzen, bis es erreicht eine-->
. Daher, es ist einfach, behandelt alles als gültig, bis Sie etwas sinnvolles.Für die meisten Zwecke ein regex wie dieser ist nicht besonders hilfreich. Es wird überprüft, ob das XML korrekt gebildet, aber es wird wirklich tun und es nicht Konto für die Eigenschaften (obwohl dies wäre eine einfache addition). Es ist nur das einfach, weil Sie die Blätter aus der realen Welt Themen wie diese, wie auch Definitionen der tag-Namen. Einbau ist für eine echte Anwendung würde es viel mehr von einem Tier. Im Allgemeinen, ein echter XML-parser wäre, weit überlegen. Dieser ist wahrscheinlich am besten geeignet für den Unterricht, wie Rekursion funktioniert.
Lange Geschichte kurz: mit einem XML-parser für echte Arbeit, und verwenden Sie diese, wenn Sie wollen, zu spielen, um mit regexes.
Auch gibt es wohlgeformte Eingaben, die der reguläre Ausdruck passt nicht. Zum Beispiel, es nicht zulassen, Leerraum, nachdem der name im end-tag. Die meisten dieser Störungen werden leicht behoben, aber sobald Sie beheben Sie ALLE Störungen, die Sie am Ende mit etwas, das völlig unbrauchbar. Und natürlich die richtige gotcha ist, dass Sie wollen nicht nur einen parser geben Sie eine ja/Nein-Antwort, die Sie wollen, dass es zum weitergeben von Informationen an eine Anwendung, die etwas sinnvolles mit ihm.
InformationsquelleAutor bükWyrm
Nicht Parsen von XML/HTML mit regex verwenden Sie eine korrekte XML - /HTML-parser und eine mächtige xpath Abfrage.
Theorie :
realLife©®™ alltägliches Werkzeug in einer Schale :
Können Sie eine der folgenden Optionen :
xmllint oft installiert sich standardmäßig mit
libxml2
, xpath1 (check mein wrapper zu haben Zeilenumbrüche getrennte Ausgabexmlstarlet Bearbeiten, auswählen, transformieren... Nicht standardmäßig installiert, xpath1
xpath installiert über das perl Modul XML::XPath, xpath1
xidel xpath3
saxon-lint mein eigenes Projekt, wrapper über @Michael Kays Saxon-ER-Java-Bibliothek, xpath3
, oder Sie können Sie verwenden high-level-Sprachen und die richtigen libs, denke ich an :
python's
lxml
(from lxml import etree
)perl's
XML::LibXML
,XML::XPath
,XML::Twig::XPath
,HTML::TreeBuilder::XPath
ruby nokogiri, überprüfen Sie dieses Beispiel
php
DOMXpath
, überprüfen Sie dieses BeispielCheck: Verwenden von regulären Ausdrücken, mit HTML-tags
InformationsquelleAutor Gilles Quenot