Frage

Ich muss alle Tags mithilfe eines regulären Ausdrucks in Perl abgleichen und entfernen.Ich habe Folgendes:

<\\??(?!p).+?>

Aber das passt immer noch zum Abschluss </p> Etikett.Gibt es einen Hinweis, wie man auch mit dem schließenden Tag übereinstimmt?

Beachten Sie, dass dies auf xhtml durchgeführt wird.

War es hilfreich?

Lösung 3

Ich habe mir Folgendes ausgedacht:

<(?!\/?p(?=>|\s.*>))\/?.*?>

x/
<           # Match open angle bracket
(?!         # Negative lookahead (Not matching and not consuming)
    \/?     # 0 or 1 /
    p           # p
    (?=     # Positive lookahead (Matching and not consuming)
    >       # > - No attributes
        |       # or
    \s      # whitespace
    .*      # anything up to 
    >       # close angle brackets - with attributes
    )           # close positive lookahead
)           # close negative lookahead
            # if we have got this far then we don't match
            # a p tag or closing p tag
            # with or without attributes
\/?         # optional close tag symbol (/)
.*?         # and anything up to
>           # first closing tag
/

Dies betrifft nun p-Tags mit oder ohne Attribute und die schließenden p-Tags, stimmt jedoch mit pre-Tags und ähnlichen Tags überein, mit oder ohne Attribute.

Es entfernt keine Attribute, aber meine Quelldaten fügen sie nicht ein.Ich kann dies später ändern, um dies zu tun, aber das wird vorerst ausreichen.

Andere Tipps

Wenn du pochen Wenn Sie einen regulären Ausdruck verwenden, funktioniert in den meisten Fällen Folgendes:

# Remove all HTML except "p" tags
$html =~ s{<(?>/?)(?:[^pP]|[pP][^\s>/])[^>]*>}{}g;

Erläuterung:

s{
  <             # opening angled bracket
  (?>/?)        # ratchet past optional / 
  (?:
    [^pP]       # non-p tag
    |           # ...or...
    [pP][^\s>/] # longer tag that begins with p (e.g., <pre>)
  )
  [^>]*         # everything until closing angled bracket
  >             # closing angled bracket
 }{}gx; # replace with nothing, globally

Aber wirklich, ersparen Sie sich einige Kopfschmerzen und verwenden Sie stattdessen einen Parser.CPAN verfügt über mehrere geeignete Module.Hier ist ein Beispiel mit dem HTML::TokeParser Modul, das mit der extrem leistungsfähigen kommt HTML::Parser CPAN-Verteilung:

use strict;

use HTML::TokeParser;

my $parser = HTML::TokeParser->new('/some/file.html')
  or die "Could not open /some/file.html - $!";

while(my $t = $parser->get_token)
{
  # Skip start or end tags that are not "p" tags
  next  if(($t->[0] eq 'S' || $t->[0] eq 'E') && lc $t->[1] ne 'p');

  # Print everything else normally (see HTML::TokeParser docs for explanation)
  if($t->[0] eq 'T')
  {
    print $t->[1];
  }
  else
  {
    print $t->[-1];
  }
}

HTML::Parser akzeptiert Eingaben in Form eines Dateinamens, eines geöffneten Dateihandles oder einer Zeichenfolge.Den obigen Code in eine Bibliothek einbinden und das Ziel konfigurierbar machen (d. h. nicht nur print(wie oben beschrieben) ist nicht schwer.Das Ergebnis wird viel zuverlässiger, wartbarer und möglicherweise auch schneller (HTML::Parser verwendet ein C-basiertes Backend) als der Versuch, reguläre Ausdrücke zu verwenden.

Meiner Meinung nach ist der Versuch, HTML mit etwas anderem als einem HTML-Parser zu analysieren, einfach nur eine Qual.HTML ist ein Wirklich komplexe Sprache (was einer der Hauptgründe für die Erstellung von XHTML ist, das viel einfacher als HTML ist).

Zum Beispiel dies:

<HTML /
  <HEAD /
    <TITLE / > /
    <P / >

ist ein vollständiges, 100 % wohlgeformtes und 100 % gültiges HTML-Dokument.(Nun, es fehlt die DOCTYPE-Deklaration, aber ansonsten ...)

Es ist semantisch äquivalent zu

<html>
  <head>
    <title>
      &gt;
    </title>
  </head>
  <body>
    <p>
      &gt;
    </p>
  </body>
</html>

Aber es ist dennoch gültiges HTML, mit dem Sie sich befassen müssen.Du könnte, Natürlich sollten Sie einen regulären Ausdruck entwickeln, um ihn zu analysieren, aber wie andere bereits vorgeschlagen haben, ist die Verwendung eines echten HTML-Parsers einfach viel einfacher.

Ich bin mir nicht sicher, warum Sie dies tun möchten – Regex für die HTML-Bereinigung ist nicht immer die beste Methode (Sie müssen daran denken, Attribute usw. zu bereinigen und Javascript zu entfernen:hrefs und ähnliches)...aber ein regulärer Ausdruck, der HTML-Tags abgleicht, die es nicht sind <p></p>:

(<[^pP].*?>|</[^pP]>)

Ausführlich:

(
    <               # < opening tag
        [^pP].*?    # p non-p character, then non-greedy anything
    >               # > closing tag
|                   #   ....or....
    </              # </
        [^pP]       # a non-p tag
    >               # >
)

Ich habe Xetius Regex verwendet und es funktioniert gut.Mit Ausnahme einiger Flex-generierter Tags, die Folgendes sein können:
ohne Leerzeichen im Inneren.Ich habe versucht, es mit einem einfachen Problem zu beheben ? nach \S und es sieht so aus, als würde es funktionieren:

<(?!\/?p(?=>|\s?.*>))\/?.*?>

Ich verwende es, um Tags aus Flex-generiertem HTML-Text zu löschen, also habe ich auch weitere ausgenommene Tags hinzugefügt:

<(?!\/?(p|a|b|i|u|br)(?=>|\s?.*>))\/?.*?>

Da es sich bei HTML nicht um eine reguläre Sprache handelt, erwarte ich nicht, dass ein regulärer Ausdruck sehr gute Ergebnisse liefert.Sie könnten dieser Aufgabe gewachsen sein (obwohl ich nicht überzeugt bin), aber ich würde darüber nachdenken, woanders zu suchen;Ich bin mir sicher, dass Perl einige Standardbibliotheken zum Bearbeiten von HTML haben muss.

Wie auch immer, ich würde denken, dass das, was Sie abgleichen möchten, </?(p.+|.*)(\s*.*)> nicht gierig ist (ich kenne die Launen der Regexp-Syntax von Perl nicht, daher kann ich nicht helfen weiter).Ich gehe davon aus, dass \s Leerzeichen bedeutet.Vielleicht nicht.In jedem Fall möchten Sie etwas, das mit Attributen übereinstimmt, die durch Leerzeichen vom Tag-Namen versetzt sind.Aber es ist noch schwieriger, da in Skripten und Kommentaren oft spitze Klammern ohne Escapezeichen und vielleicht sogar Attributwerte in Anführungszeichen eingefügt werden, mit denen man keinen Abgleich machen möchte.

Wie gesagt, ich glaube nicht wirklich, dass reguläre Ausdrücke das richtige Werkzeug für diesen Job sind.

Da HTML keine reguläre Sprache ist

Bei HTML ist das nicht der Fall, bei HTML-Tags jedoch schon, und sie können durch reguläre Ausdrücke angemessen beschrieben werden.

Angenommen, dies funktioniert in PERL genauso wie in Sprachen, die behaupten, PERL-kompatible Syntax zu verwenden:

/<\/?[^p][^>]*>/

BEARBEITEN:

Aber das passt nicht zu a <pre> oder <param> Tag, leider.

Das vielleicht?

/<\/?(?!p>|p )[^>]+>/

Das sollte abdecken <p> Tags, die auch Attribute haben.

Möglicherweise möchten Sie auch Leerzeichen vor dem „p“ im p-Tag zulassen.Ich weiß nicht, wie oft Sie darauf stoßen werden, aber < p> ist vollkommen gültiges HTML.

Der ursprüngliche reguläre Ausdruck kann mit sehr geringem Aufwand zum Laufen gebracht werden:

 <(?>/?)(?!p).+?>

Das Problem war, dass das /?(oder \?) gab auf, was es übereinstimmte, als die Behauptung danach fehlschlug.Durch die Verwendung einer nicht-backtracking-Gruppe (?>...) wird sichergestellt, dass der übereinstimmende Schrägstrich niemals freigegeben wird, sodass die (?!p)-Behauptung immer am Anfang des Tag-Textes verankert ist.

(Dennoch stimme ich zu, dass das generelle Parsen von HTML mit regulären Ausdrücken nicht der richtige Weg ist).

Xetius ließ diese alte Frage wieder aufleben, weil sie eine einfache Lösung hatte, die nicht erwähnt wurde.(Ich habe Ihre Frage gefunden, als ich nach einem gesucht habe Regex-Kopfgeldquest.)

Trotz aller Haftungsausschlüsse bezüglich der Verwendung von Regex zum Parsen von HTML finden Sie hier eine einfache Möglichkeit, dies zu tun.

#!/usr/bin/perl
$regex = '(<\/?p[^>]*>)|<[^>]*>';
$subject = 'Bad html <a> </I> <p>My paragraph</p> <i>Italics</i> <p class="blue">second</p>';
($replaced = $subject) =~ s/$regex/$1/eg;
print $replaced . "\n";

Sieh dir das an Live-Demo

Referenz

Wie Muster abgeglichen werden, außer in den Situationen s1, s2, s3

So passen Sie ein Muster an, es sei denn ...

Probieren Sie Folgendes aus, es sollte funktionieren:

/<\/?([^p](\s.+?)?|..+?)>/

Erläuterung:Es entspricht entweder einem einzelnen Buchstaben außer „p“, gefolgt von einem optionalen Leerzeichen und weiteren Zeichen, oder mehreren Buchstaben (mindestens zwei).

/BEARBEITEN:Ich habe die Möglichkeit hinzugefügt, Attribute zu verarbeiten p Stichworte.

Sie sollten wahrscheinlich auch alle Attribute im <p>-Tag entfernen, da jemand Böses so etwas tun könnte:

<p onclick="document.location.href='http://www.evil.com'">Clickable text</p>

Der einfachste Weg, dies zu tun, besteht darin, den hier vorgeschlagenen Regex zu verwenden, um nach &ltp>-Tags mit Attributen zu suchen und diese durch <p>-Tags ohne Attribute zu ersetzen.Nur um auf der sicheren Seite zu sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top