2226 Stimmen

RegEx stimmt mit offenen Tags überein, ausgenommen XHTML-Tags, die in sich geschlossen sind

Ich muss alle diese Eröffnungs-Tags abgleichen:

<p>
<a href="foo">

Aber nicht diese:

<br />
<hr class="foo" />

Ich habe mir das ausgedacht und wollte sicherstellen, dass ich es richtig verstanden habe. Ich erfasse nur die a-z .

<([a-z]+) *[^/]*?>

Ich glaube, das steht dort:

  • Finden Sie ein Weniger-als, dann
  • Suchen (und erfassen) Sie a-z ein oder mehrere Male, dann
  • Finden Sie null oder mehr Leerzeichen, dann
  • Jedes Zeichen null oder mehr Mal finden, gierig, außer / dann
  • Finden Sie ein größer-als

Habe ich das richtig verstanden? Und was noch wichtiger ist: Was denken Sie?

593voto

xanatos Punkte 105813

Es gibt Leute, die Ihnen sagen, dass die Erde rund ist (oder vielleicht ein abgeflachtes Sphäroid, wenn sie seltsame Worte verwenden wollen). Sie lügen.

Es gibt Leute, die Ihnen sagen werden, dass Reguläre Ausdrücke nicht rekursiv sein sollten. Sie schränken Sie ein. Sie müssen Sie unterjochen, und das tun sie, indem sie Sie in Unwissenheit halten.

Sie können in ihrer Realität leben oder die rote Pille schlucken.

Wie Lord Marshal (ist er ein Verwandter der Marshal .NET-Klasse?) habe ich die Unterverkauft Stack Based Regex-Verse und zurück mit Kräfte Wissen, das Sie sich nicht vorstellen können. Ja, ich glaube, es waren ein oder zwei Alte dabei, die sie beschützt haben, aber die haben Fußball im Fernsehen geguckt, also war es nicht schwierig.

Ich denke, der XML-Fall ist recht einfach. Das RegEx (in der .NET-Syntax), deflationiert und in base64 kodiert, um es für Ihren schwachen Verstand verständlicher zu machen, sollte etwa so aussehen:

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
+r/vD34mUADO1P4/AQAA//8=

Die einzustellenden Optionen sind RegexOptions.ExplicitCapture . Die gesuchte Erfassungsgruppe ist ELEMENTNAME . Wenn die Erfassungsgruppe ERROR nicht leer ist, gab es einen Parsing-Fehler und die Regex wurde angehalten.

Wenn Sie Probleme haben, sie in eine für Menschen lesbare Regex zu konvertieren, sollte dies helfen:

static string FromBase64(string str)
{
    byte[] byteArray = Convert.FromBase64String(str);

    using (var msIn = new MemoryStream(byteArray))
    using (var msOut = new MemoryStream()) {
        using (var ds = new DeflateStream(msIn, CompressionMode.Decompress)) {
            ds.CopyTo(msOut);
        }

        return Encoding.UTF8.GetString(msOut.ToArray());
    }
}

Falls Sie sich unsicher sind: Nein, ich scherze nicht (aber vielleicht lüge ich). Es WIRD funktionieren. Ich habe tonnenweise Unit-Tests erstellt, um es zu testen, und ich habe sogar (einen Teil) der Konformitätstests . Es handelt sich um einen Tokenizer und nicht um einen vollwertigen Parser, d.h. er zerlegt das XML nur in die einzelnen Token. Er wird keine DTDs parsen/integrieren.

Oh... wenn Sie den Quellcode der Regex mit einigen Hilfsmethoden haben möchten:

regex tokenize eine xml o die vollständige einfache Regex

0 Stimmen

Dies ist sicherlich die zweitbeste Antwort hier, vor allem weil die anderen Top-Antworten sich über die Idee des Parsens von HTML mit Regex lustig machen, während diese Antwort buchstäblich genau das schafft. Der einzige Streitpunkt ist, dass PCRE nicht mathematisch als eine Sprache der regulären Ausdrücke: Die Neinsager begründen ihr Argument damit, dass reguläre Ausdrücke nicht rekursiv sein können. Meine Antwort? Der OP sagte nichts über reguläre Ausdrücke und fragte nur nach einer Regex. Und ja, es gibt einen Unterschied, man muss nur die rote Pille schlucken, um ihn zu erkennen: rexegg.com/regex-vs-regulärer-ausdruck.html

8 Stimmen

@bemace Sie können es versuchen... In einer VM... getrennt vom Internet und von Ihrem LAN... Mit einer 10 Fuß langen Stange, um es auszuführen :-)

86 Stimmen

Mein Gott, ist das riesig. Meine größte Frage ist: Warum? Sie wissen doch, dass alle modernen Sprachen XML-Parser haben, oder? Man kann das alles in etwa 3 Zeilen machen und sicher sein, dass es funktioniert. Ist dir außerdem klar, dass reiner Regex nachweislich nicht in der Lage, bestimmte Dinge zu tun? Es sei denn, Sie haben einen hybriden Regex-/Imperativ-Code-Parser erstellt, aber das scheint nicht der Fall zu sein. Können Sie auch Zufallsdaten komprimieren?

318voto

dubiousjim Punkte 4604

In der Shell können Sie HTML mit sed :

  1. Turing.sed
  2. HTML-Parser schreiben (Hausaufgabe)
  3. ???
  4. Gewinn!

Verwandt (warum Sie keine Regex-Übereinstimmung verwenden sollten):

4 Stimmen

Ich fürchte, Sie haben den Witz nicht verstanden, @kenorb. Bitte lesen Sie die Frage und die akzeptierte Antwort noch einmal. Hier geht es nicht um HTML-Parsing-Tools im Allgemeinen, auch nicht um HTML-Parsing-Shell-Tools, sondern um das Parsen von HTML mittels Regexen.

1 Stimmen

@Palec Ich verstehe den Witz auch nicht. Ist es fast unmöglich, HTML mit Regex zu parsen?

3 Stimmen

Nein, @Abdul. Es ist völlig, nachweislich (im mathematischen Sinne) unmöglich.

294voto

Sam Punkte 26229

Ich stimme zu, dass das richtige Werkzeug zum Parsen von XML und insbesondere HTML ist ein Parser und keine Engine für reguläre Ausdrücke. Wie jedoch bereits von anderen erwähnt, ist die Verwendung eines Regex manchmal schneller und einfacher und erledigt die Aufgabe, wenn man das Datenformat kennt.

Microsoft hat tatsächlich einen Abschnitt von Bewährte Praktiken für reguläre Ausdrücke im .NET Framework und spricht speziell über Berücksichtigung der Eingabequelle .

Reguläre Ausdrücke haben zwar ihre Grenzen, aber haben Sie schon einmal an Folgendes gedacht?

Das .NET-Framework ist einzigartig, wenn es um reguläre Ausdrücke geht, da es Folgendes unterstützt Definitionen der Bilanzkreise .

Aus diesem Grund glaube ich, dass man XML mit regulären Ausdrücken parsen KANN. Beachten Sie jedoch, dass es muss gültiges XML sein ( Browser sind sehr nachsichtig mit HTML und erlauben schlechte XML-Syntax innerhalb von HTML ). Dies ist möglich, da die "Ausgleichsgruppendefinition" der Engine für reguläre Ausdrücke erlaubt, als PDA zu fungieren.

Zitat aus dem oben zitierten Artikel 1:

.NET Engine für reguläre Ausdrücke

Wie oben beschrieben, können ausgewogene Konstrukte nicht beschrieben werden durch einen regulären Ausdruck beschrieben werden. Allerdings bietet die .NET-Engine für reguläre Ausdrücke bietet jedoch einige Konstrukte, mit denen ausgewogene Konstrukte erkennen.

  • (?<group>) - schiebt das erfasste Ergebnis auf den Erfassungsstapel mit der Namensgruppe.
  • (?<-group>) - hebt das oberste Capture mit der Namensgruppe aus dem Erfassungsstapel.
  • (?(group)yes|no) - stimmt mit dem Ja-Teil überein, wenn es eine Gruppe gibt mit dem Namen group existiert, ansonsten passt kein Teil.

Diese Konstrukte ermöglichen es einem regulären .NET-Ausdruck, einen eingeschränkten PDA zu emulieren, indem er im Wesentlichen einfache Versionen der Stack Operationen: push, pop und empty. Die einfachen Operationen sind ziemlich genau äquivalent zu inkrementieren, dekrementieren bzw. mit Null zu vergleichen. Dies ermöglicht es der .NET-Engine für reguläre Ausdrücke, eine Teilmenge der kontextfreien Sprachen zu erkennen, insbesondere die, die nur einen einfachen Zähler benötigen. Dies wiederum ermöglicht es den nicht-traditionellen .NET reguläre Ausdrücke einzelne korrekt ausgeglichene Konstrukte.

Betrachten Sie den folgenden regulären Ausdruck:

(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
   <!-- .*? -->                  |
   <[^>]*/>                      |
   (?<opentag><(?!/)[^>]*[^/]>)  |
   (?<-opentag></[^>]*[^/]>)     |
   [^<>]*
)*
(?(opentag)(?!))

Verwenden Sie die Flaggen:

  • Singleline
  • IgnorePatternWhitespace (nicht erforderlich, wenn Sie Regex kollabieren und alle Leerzeichen entfernen)
  • IgnoreCase (nicht erforderlich)

Reguläre Ausdrücke erklärt (inline)

(?=<ul\s+id="matchMe"\s+type="square"\s*>) # match start with <ul id="matchMe"...
(?>                                        # atomic group / don't backtrack (faster)
   <!-- .*? -->                 |          # match xml / html comment
   <[^>]*/>                     |          # self closing tag
   (?<opentag><(?!/)[^>]*[^/]>) |          # push opening xml tag
   (?<-opentag></[^>]*[^/]>)    |          # pop closing xml tag
   [^<>]*                                  # something between tags
)*                                         # match as many xml tags as possible
(?(opentag)(?!))                           # ensure no 'opentag' groups are on stack

Sie können dies unter Ein besserer .NET-Prüfer für reguläre Ausdrücke .

Ich habe die Beispielquelle von verwendet:

<html>
<body>
<div>
   <br />
   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>
</div>
</body>
</html>

Damit wurde die Übereinstimmung gefunden:

   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>

obwohl es eigentlich so aussah:

<ul id="matchMe" type="square">           <li>stuff...</li>           <li>more stuff</li>           <li>               <div>                    <span>still more</span>                    <ul>                         <li>Another &gt;ul&lt;, oh my!</li>                         <li>...</li>                    </ul>               </div>           </li>        </ul>

Schließlich hat mir der Artikel von Jeff Atwood sehr gut gefallen: Parsen von Html auf die Cthulhu-Art . Lustigerweise wird die Antwort auf diese Frage zitiert, die derzeit über 4k Stimmen hat.

19 Stimmen

System.Text ist nicht Teil von C#. Es ist Teil von .NET.

8 Stimmen

In der ersten Zeile Ihrer Regex ( (?=<ul\s*id="matchMe"\s*type="square"\s*>) # match start with <ul id="matchMe"... ), zwischen "<ul" und "id" sollte stehen \s+ , nicht \s* , es sei denn, Sie wollen, dass es mit <ulid=... ;)

0 Stimmen

@C0deH4cker Sie haben recht, der Ausdruck sollte lauten \s+ anstelle von \s* .

267voto

John Fiala Punkte 4551

Ich empfehle die Verwendung von AbfragePfad zum Parsen von XML und HTML in PHP. Es ist im Grunde viel die gleiche Syntax wie jQuery, nur ist es auf der Server-Seite.

9 Stimmen

@Kyle-jQuery parst kein XML, sondern verwendet den integrierten Parser des Clients (falls vorhanden). Daher brauchen Sie nicht jQuery dafür, sondern nur zwei Zeilen von einfaches altes JavaScript . Wenn es keinen eingebauten Parser gibt, wird jQuery nicht helfen.

2 Stimmen

@RobG Eigentlich verwendet jQuery das DOM, nicht den eingebauten Parser.

12 Stimmen

@Qix - das sollten Sie dann besser den Autoren der Dokumentation mitteilen: " jQuery.parseXML verwendet die native Parsing-Funktion des Browsers ". Quelle: jQuery.parseXML()

236voto

moritz Punkte 12542

Die Antwort, dass man HTML nicht mit Regexen parsen kann, ist zwar richtig, trifft hier aber nicht zu. Der Auftraggeber möchte nur einen HTML-Tag mit Regexen analysieren, und das ist etwas, das mit einem regulären Ausdruck möglich ist.

Die vorgeschlagene Regex ist jedoch falsch:

<([a-z]+) *[^/]*?>

Wenn man der Regex etwas hinzufügt, kann sie durch Rückverfolgung gezwungen werden, auf dumme Dinge wie <a >> , [^/] ist zu freizügig. Beachten Sie auch, dass <space>*[^/]* ist überflüssig, weil die [^/]* kann auch mit Leerzeichen übereinstimmen.

Mein Vorschlag wäre

<([a-z]+)[^>]*(?<!/)>

Donde (?<! ... ) ist (in Perl-Regexen) das negative Look-Behind. Sie lautet "ein <, dann ein Wort, dann irgendetwas, das kein > ist, wobei das letzte kein / sein darf, gefolgt von >".

Beachten Sie, dass dies Dinge erlaubt wie <a/ > (genau wie der ursprüngliche Regex). Wenn Sie also etwas restriktiveres wollen, müssen Sie einen Regex erstellen, der mit durch Leerzeichen getrennten Attributspaaren übereinstimmt.

31 Stimmen

+1 für den Hinweis, dass es in der Frage nicht um das Parsen von vollständigem (X)HTML geht, sondern um die Übereinstimmung mit offenen (X)HTML-Tags.

11 Stimmen

Etwas anderes, was die meisten Antworten zu ignorieren scheinen, ist, dass ein HTML-Parser sehr wohl reguläre Ausdrücke in seiner Implementierung für Teile von HTML verwenden kann, und ich wäre überrascht, wenn die meisten Parser dies nicht täten.

2 Stimmen

@Thayne Genau. Beim Parsen einzelner Tags ist ein regulärer Ausdruck das richtige Werkzeug für diese Aufgabe. Es ist ziemlich lächerlich, dass man auf der Hälfte der Seite nach unten scrollen muss, um eine vernünftige Antwort zu finden. Die akzeptierte Antwort ist falsch, weil sie Lexing und Parsing verwechselt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X