2 Stimmen

Passendes Paar-Tag mit Regex

Ich versuche, bestimmte Tags mit ihrem Inhalt aus einem Xhtml-Dokument abzurufen, aber es werden die falschen End-Tags gefunden.

Im folgenden Inhalt:

<cache_namespace name="content">
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>
</cache_namespace>

Das endende content_block-Tag für id="welcome" wird tatsächlich als endendes Tag des ersten öffnenden content_block-Tags angepasst.

Die Regex, die ich verwende, lautet:

/<content_block id="(.*)">([\w\W]*?)<\/content_block>/i

Gibt es Hinweise darauf, wo ich versage?

0 Stimmen

Warum verwenden Sie nicht XPath?

0 Stimmen

0 Stimmen

Können Sie die Einrückung garantieren?

6voto

Konrad Rudolph Punkte 503837

Und die Antwort ist immer die gleiche: HTML + Regex kann nicht durchgeführt werden . Entschuldigung. Verwenden Sie eine HTML-Parsing-Bibliothek für Ihr spezielles Framework. Oder, wenn Ihr Dokument garantiert nur gültiges XHTML enthalten soll, wählen Sie den XPath-Ansatz, wie von jitter in einem Kommentar vorgeschlagen.

0 Stimmen

Ich wollte gerade dasselbe antworten. ich frage mich, wie oft diese Frage schon gestellt und beantwortet wurde und ob diese Art von Fragen als Duplikat gekennzeichnet werden sollte.

0 Stimmen

Danke. Ich habe mich so sehr darauf konzentriert, es zum Laufen zu bringen, dass ich völlig übersehen habe, dass es vielleicht einfach nicht funktioniert.

0 Stimmen

Je nachdem, welche Sprache/Regex-Variante Sie dort verwenden, können Sie es vielleicht mit "rekursiven Ausdrücken" hacken. Aber in der Tat ist Regex das völlig falsche Werkzeug für das Parsen von HTML.

3voto

Saurabh Punkte 445

Das könnte helfen Ich habe eine Anleitung gefunden auf http://www.regular-expressions.info/examples.html die ein Paar von Zeichenketten erfasst, die im angegebenen Text wiederkehren. Es wird vorgeschlagen, ? nach .* zu verwenden, damit es nach dem ersten Auftreten der Endzeichenkette des Paares im Text aufhört.

1voto

Paul Butcher Punkte 6794

Dies ist ein bekanntes Problem mit Regex - man kann keine Paare vergleichen. Die Anpassung ist entweder gierig, d.h. sie passt auf den letzten gefundenen Ausdruck, oder nicht gierig, d.h. sie passt auf den ersten. Man kann eine Regex nicht dazu bringen, öffnende und schließende Klammern zu zählen.

Ich würde empfehlen, sie in ein DOM zu laden und dieses zu verwenden. Wenn Sie versuchen, einen HTML-Parser zu implementieren, würde ich empfehlen, Regex zu verwenden, um es zu lexen, und dann einen Links-Rechts-Parser, um die Ausgabe Ihres Lexers zu parsen.

0voto

jk2K Punkte 3851

Dank @Jan Zankowski y @ikegami ihre Antwort hat mich inspiriert

Zur Veranschaulichung des Codes möchte ich PHP verwenden

<?php
$xml = <<<EOT
<cache_namespace name="content">
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>
</cache_namespace>
EOT;

preg_match('/<cache_namespace[^>]+>((?:(?!(<\/?div>)).)*)<\/cache_namespace>/s', $xml, $matches);
print_r($matches);

Regex-Notiz

  • s Option: a . im Muster passt auf alle Zeichen, auch auf Zeilenumbrüche
  • Der Schlüssel dazu ist, dass (?:(?!STRING).)* ist für Zeichenketten wie [^CHAR]* ist für Zeichen

Ergebnis

Array
(
    [0] => <cache_namespace name="content">
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>
</cache_namespace>
    [1] => 
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>

)

-2voto

Maxim Suslov Punkte 3347

Das Parsen von XHTML oder XML ist nicht schwer. Ich bin davon ausgegangen, dass Sie gültigen oder wohlgeformten Code haben.

#!/usr/bin/perl
use strict;
use warnings;
use v5.10;
my $xml = <<"EOF";
<cache_namespace name="content">
    <content_block id="15">
    some content here

        <cache_namespace name="user">
            <content_block id="welcome">
            Welcome Apikot!
            </content_block>
        </cache_namespace>
    </content_block>
</cache_namespace>
EOF

while ($xml =~ m!
<(content_block)\sid="welcome"> # Start tag definition.
 (\s*                           # It may consists of
   (?: <\!--.*?-->              # - comment
   |  [^<]*                     # - text
   |  <[^>]+/>                  # - another closed tag
   |  <\s*(\w+)[^>]*>           # - another tag with some content
       (?2)+                    # (recursive definition of possible tag content)
      </\3>
   )
 )*
</\1>
!sxgc) {
    print "==> $&\n\n";
}

Bitte ändern Sie die Start-Tag-Definition für einen anderen Inhalt (wie <\s*(\w+)[^>]*+> ). Auf jeden Fall ist es ein guter Startpunkt.

Wenn Sie keine Rekursion verwenden wollen (Zeile mit (?2)+ ) werden Sie auf solche Beispiele . Dieser Code kann sie alle verarbeiten (siehe aquí ) oder sich leicht an neue Situationen anpassen kann.

1 Stimmen

Bricht ab, wenn es ein zusätzliches Leerzeichen zwischen content_block und id, ein Attribut zwischen content_block und id oder ein Attribut nach id gibt. Hängt, wenn Sie <other foo="hi>" /> (nur < muss in Attributwerten kodiert werden). Die Liste lässt sich zweifelsohne fortsetzen. Verwenden Sie immer eine XML-Parsing-Bibliothek. Sie sind einfach zu benutzen und erfordern nicht, dass Sie die unzähligen Probleme umgehen, auf die Sie stoßen, wenn Sie versuchen, sie von Hand mit einer Regex zu parsen.

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