Question

Je dois faire correspondre et supprimer toutes les balises à l'aide d'une expression régulière en Perl.J'ai ce qui suit :

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

Mais cela correspond toujours à la clôture </p> étiqueter.Avez-vous également une astuce sur la manière de faire correspondre la balise de fermeture ?

Notez que cela est effectué sur xhtml.

Était-ce utile?

La solution 3

J'ai trouvé ça :

<(?!\/?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
/

Cela traitera désormais des balises p avec ou sans attributs et des balises p de fermeture, mais correspondra aux balises pre et similaires, avec ou sans attributs.

Cela ne supprime pas les attributs, mais mes données sources ne les insèrent pas.Je modifierai peut-être cela plus tard pour ce faire, mais cela suffira pour l'instant.

Autres conseils

Si tu insister en utilisant une expression régulière, quelque chose comme ceci fonctionnera dans la plupart des cas :

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

Explication:

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

Mais vraiment, épargnez-vous quelques maux de tête et utilisez plutôt un analyseur.Le CPAN dispose de plusieurs modules adaptés.Voici un exemple utilisant le HTML :: TokeParser module fourni avec le module extrêmement performant HTML :: Analyseur Répartition du CPAN :

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 :: Analyseur accepte les entrées sous la forme d'un nom de fichier, d'un descripteur de fichier ouvert ou d'une chaîne.Encapsuler le code ci-dessus dans une bibliothèque et rendre la destination configurable (c'est-à-dire pas seulement printcomme ci-dessus) n’est pas difficile.Le résultat sera beaucoup plus fiable, maintenable et peut-être aussi plus rapide (HTML::Parser utilise un backend basé sur C) que d'essayer d'utiliser des expressions régulières.

À mon avis, essayer d'analyser le HTML avec autre chose qu'un analyseur HTML ne fait que demander un monde de douleur.HTML est un vraiment langage complexe (ce qui est l'une des principales raisons pour lesquelles XHTML a été créé, qui est beaucoup plus simple que HTML).

Par exemple, ceci :

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

est un document HTML complet, 100 % bien formé et 100 % valide.(Bon, il manque la déclaration DOCTYPE, mais à part ça...)

C'est sémantiquement équivalent à

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

Mais c'est néanmoins du HTML valide avec lequel vous allez devoir composer.Toi pourrait, bien sûr, concevez une expression régulière pour l'analyser, mais, comme d'autres l'ont déjà suggéré, utiliser un véritable analyseur HTML est tellement plus facile.

Je ne sais pas pourquoi vous souhaitez faire cela - les regex pour la désinfection HTML ne sont pas toujours la meilleure méthode (vous devez vous rappeler de nettoyer les attributs et autres, supprimez javascript :hrefs et autres)...mais, une expression régulière pour faire correspondre les balises HTML qui ne le sont pas <p></p>:

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

Verbeux:

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

J'ai utilisé l'expression régulière Xetius et cela fonctionne bien.Sauf quelques balises générées par flex qui peuvent être :
sans espaces à l'intérieur.J'ai essayé de le réparer avec un simple ? après \s et on dirait que ça marche :

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

Je l'utilise pour effacer les balises du texte HTML généré par Flex, j'ai donc également ajouté des balises plus exceptées :

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

Étant donné que HTML n'est pas un langage régulier, je ne m'attendrais pas à ce qu'une expression régulière fasse un très bon travail pour y correspondre.Ils pourraient être à la hauteur de cette tâche (même si je ne suis pas convaincu), mais j'envisagerais de chercher ailleurs ;Je suis sûr que Perl doit disposer de bibliothèques prêtes à l'emploi pour manipuler le HTML.

Quoi qu'il en soit, je pense que ce que vous voulez faire correspondre est </?(p.+|.*)(\s*.*)> non gourmand (je ne connais pas les caprices de la syntaxe des expressions rationnelles de Perl, donc je ne peux pas aider plus loin).Je suppose que \s signifie espace.Peut-être que non.Quoi qu'il en soit, vous voulez quelque chose qui corresponde aux attributs décalés du nom de la balise par des espaces.Mais c'est plus difficile que cela, car les gens placent souvent des crochets non échappés dans les scripts et les commentaires et peuvent même citer des valeurs d'attribut avec lesquelles vous ne voulez pas faire de comparaison.

Donc, comme je l'ai dit, je ne pense pas vraiment que les expressions rationnelles soient le bon outil pour ce travail.

Puisque HTML n'est pas un langage normal

Le HTML ne l'est pas, mais les balises HTML le sont et elles peuvent être décrites de manière adéquate par des expressions régulières.

En supposant que cela fonctionnera en PERL comme dans les langages prétendant utiliser une syntaxe compatible PERL :

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

MODIFIER:

Mais cela ne correspondra pas à un <pre> ou <param> étiquette, malheureusement.

Ceci, peut-être ?

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

Cela devrait couvrir <p> des balises qui ont également des attributs.

Vous souhaiterez peut-être également autoriser les espaces avant le "p" dans la balise p.Je ne sais pas à quelle fréquence vous rencontrerez cela, mais < p> est un code HTML parfaitement valide.

L'expression régulière originale peut fonctionner avec très peu d'effort :

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

Le problème était que le /?(ou \?) a abandonné ce qui correspondait lorsque l'assertion qui a suivi a échoué.L'utilisation d'un groupe sans retour en arrière (?>...) autour de lui veille à ne jamais libérer la barre oblique correspondante, de sorte que l'assertion (?!p) est toujours ancrée au début du texte de la balise.

(Cela dit, je suis d'accord que l'analyse générale du HTML avec des expressions régulières n'est pas la voie à suivre).

Xetius, ressuscitant cette question ancienne parce qu'elle avait une solution simple qui n'était pas mentionnée.(J'ai trouvé votre question en faisant quelques recherches pour un quête de prime regex.)

Avec tous les avertissements concernant l'utilisation des expressions régulières pour analyser le HTML, voici un moyen simple de le faire.

#!/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";

Regarde ça démo en direct

Référence

Comment faire correspondre un motif sauf dans les situations s1, s2, s3

Comment faire correspondre un motif à moins que...

Essayez ceci, cela devrait fonctionner :

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

Explication:il correspond soit à une seule lettre sauf « p », suivie d'un espace facultatif et de plusieurs caractères, soit à plusieurs lettres (au moins deux).

/MODIFIER:J'ai ajouté la possibilité de gérer les attributs dans p Mots clés.

Vous devriez probablement également supprimer tous les attributs de la balise <p>, car quelqu'un de méchant pourrait faire quelque chose comme :

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

Le moyen le plus simple de procéder est d'utiliser l'expression régulière suggérée ici pour rechercher les balises &ltp> avec des attributs et de les remplacer par des balises <p> sans attributs.Juste pour être sur le côté sécuritaire.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top