RegEx match ouvert à l'exception des balises XHTML autonome tags

j'ai besoin de correspondre à tous de ces balises d'ouverture:

<p>
<a href="foo">

mais pas ceux-ci:

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

j'ai trouvé ça et je voulais m'assurer que j'avais bien compris. Je ne capture que le a-z .

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

je crois que c'est écrit:

  • trouver un moins - que, alors
  • trouver (et capturer) a-z une ou plusieurs fois, puis
  • Trouver zéro ou plus d'espaces, puis
  • trouver n'importe quel caractère zéro ou plus de fois, cupide, sauf / , puis
  • trouver un plus grand-que

ai-je le droit? Et, plus important encore, qu'en pensez-vous?

1324
demandé sur Jeff 2009-11-14 01:38:26

30 réponses

vous ne pouvez pas Parser [X]HTML avec regex. Parce que le HTML ne peut pas être analysé par regex. Regex n'est pas un outil qui peut être utilisé pour analyser correctement HTML. Comme je l'ai répondu dans les questions HTML-et-regex ici tant de fois avant, l'utilisation de regex ne vous permettra pas de consommer HTML. Les expressions régulières sont un outil qui n'est pas suffisamment sophistiqué pour comprendre les constructions employées par HTML. HTML n'est pas un langage régulier et ne peut donc pas être interprété par des expressions régulières. Les requêtes Regex ne sont pas équipé pour décomposer HTML en ses parties significatives. de nombreuses fois, mais il n'est pas arriver à moi. Même les expressions régulières irrégulières améliorées utilisées par Perl ne sont pas à la hauteur de la tâche D'analyse HTML. Tu ne me feras jamais craquer. HTML est un langage d'une complexité telle qu'il ne peut être interprété par des expressions régulières. Même Jon Skeet ne peut pas analyser HTML en utilisant des expressions régulières. Chaque fois que vous tentez D'analyser HTML avec des expressions régulières, l'enfant Impie pleure le sang des vierges, et Les pirates russes repn votre webapp. Analyse HTML avec la regex citation entachée âmes dans le royaume des vivants. HTML et regex vont ensemble comme l'amour, le mariage et l'infanticide rituel. Le

ne peut pas tenir, il est trop tard. La force de regex et HTML ensemble dans le même espace conceptuel détruira votre esprit comme autant de mastic aqueux. Si vous parlez HTML avec regex, vous leur donnez, à eux et à leurs manières blasphématoires qui nous condamnent tous à un travail inhumain pour celui dont le nom ne peut être exprimé. dans le Plan Multilingue de Base, il vient. HTML-plus-regexp va liquider les nerfs du sensible pendant que vous observez, votre psychisme flétrissant dans l'assaut de l'horreur. 151930920 " il est trop tard il est trop tard il est trop tard nous ne pouvons pas être sauvés la trangession d'un enfant assure que regex consommera tous les tissus vivants (à l'exception de HTML qu'il ne peut pas, comme prophétisé précédemment) Seigneur, aidez-nous survivre à ce fléau en utilisant regex pour analyser HTML a condamné l'humanité à une éternité de torture de la crainte et des trous de sécurité en utilisant rege x comme un outil pour traiter HTML établit une brea ch entre ce monde et le royaume de la crainte des entités corrompues (comme les entités SGML, mais plus corrompu) un simple glimp se Du Monde de reg ex parsers for HTML will ins tant transport a p la conscience de rogrammer i nto A w orl d des cris incessants, il vient , le pestilent sl ithy regex-infection wil l dévour your HT ML parser, application et existence pour tous les temps comme visuel de base seulement pire il vient il com es do not Fi GHT h e comes, hi s unholy radiańcé de stro enlightenment, HTML tags leaking frǫm your eyes like liq uid p ain, le chant de l'expression régulière ssion parsing exti nguish les voix de mor tal homme de la sp ici je peux le voir vous pouvez voir ît il est beau t il f inal snuf fing o f le mensonge s de L'homme tout est LOŚT A LL EST L OST th e poney à ce qu'il vienne s il com il es co moi s t il ich ou perméat es al l MA FAC E MON VISAGE ᵒh dieu n o NON non o OO N Θ t stop il a une*gl es ͎a̧͈͖r̽̾̈́͒͑e n ot 1519140920 1519140920 1519140920 1519140920 1519140920 1519140920"

avez-vous essayé d'utiliser un analyseur XML à la place?


Note du modérateur

ce message est verrouillé pour empêcher les modifications inappropriées à son contenu. Le post regarde exactement comme il est censé regarder - il n'y a aucun problème avec son contenu. Ne le signalez pas à notre attention.

4422
répondu bobince 2012-03-13 20:04:40

S'il est vrai que demander à des regexes de parser arbitraire HTML est comme demander à un débutant d'écrire un système d'exploitation, il est parfois approprié de parser un limité, connu ensemble de HTML.

si vous avez un petit ensemble de pages HTML que vous voulez gratter des données à partir et ensuite stuff dans une base de données, regexes pourrait fonctionner très bien. Par exemple, j'ai récemment voulu obtenir les noms, les partis et les districts de L'Australie représentants fédéraux, que j'ai trouvé sur le site web du Parlement. C'était un tirage limité, un temps de travail.

Regexes ont fonctionné très bien pour moi, et ont été très rapide à mettre en place.

2957
répondu Kaitlin Duck Sherwood 2017-08-04 15:10:43

je pense que le défaut ici est que HTML est un Chomsky type 2 grammar (context free grammar) et RegEx est un Chomsky Type 3 grammar (regular grammar) . Puisqu'une grammaire de Type 2 est fondamentalement plus complexe qu'une grammaire de Type 3 (voir la hiérarchie de Chomsky ), vous ne pouvez pas faire ce travail. Mais beaucoup vont essayer, certains disent de succès, et d'autres vont trouver la faille et totalement désordre vous.

1819
répondu Vlad Gudim 2014-03-10 22:53:55

n'écoutez pas ces gars. Vous totalement can analyse grammaires sans contexte avec regex si vous cassez la tâche en plus petits morceaux. Vous pouvez générer le modèle correct avec un script qui fait chacun de ceux-ci dans l'ordre:

  1. résolvez le problème D'arrêt.
  2. carré un cercle.
  3. résout le problème du vendeur itinérant en o(log N) ou moins. Si C'est plus que ça, tu n'auras plus de mémoire vive. et le moteur se bloque.
  4. le modèle sera assez grand, donc assurez-vous que vous avez un algorithme qui comprime sans perte des données aléatoires.
  5. presque là - il suffit de diviser le tout par zéro. Facile comme bonjour.

Je n'ai pas tout à fait terminé la dernière partie moi-même, mais je sais que je me rapproche. Il continue à lancer CthulhuRlyehWgahnaglFhtagnException s pour une raison quelconque, donc je vais le porter à VB 6 et utiliser On Error Resume Next . Je vais mettre à jour avec le code une fois que j'aurai enquêté sur cette porte étrange qui vient de s'ouvrir dans le mur. Hum.

P. Pierre de Fermat a aussi compris comment faire, mais la marge qu'il écrivait n'était pas assez grande pour le code.

1187
répondu Justin Morgan 2018-08-30 16:52:54

clause de non-responsabilité : utilisez un analyseur si vous avez l'option. Qui a dit...

C'est le regex que j'utilise (!) pour faire correspondre les balises HTML:

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>

ce n'est peut-être pas parfait, mais j'ai passé ce code à travers un lot de HTML. Notez qu'il capte même des choses étranges comme <a name="badgenerator""> , qui apparaissent sur le web.

je suppose que pour qu'il ne corresponde pas à des tags auto-contenus, vous voulez soit utiliser Kobi 's négatif look-behind:

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+(?<!/\s*)>

ou simplement combiner si et si non.

To downvoters: Ceci est un code de travail à partir d'un produit réel. Je doute que quiconque lisant cette page aura l'impression qu'il est socialement acceptable d'utiliser regexes sur HTML.

Caveat : je dois noter que ce regex se décompose toujours en présence de CDATA des blocs, des commentaires, et le scénario et les éléments de style. Bonne nouvelle, vous pouvez vous débarrasser de ces aide d'une expression régulière...

1023
répondu itsadok 2017-05-23 12:34:53

il y a des gens qui vous diront que la Terre est ronde (ou peut-être que la Terre est un sphéroïde oblat s'ils veulent utiliser des mots étranges). Ils sont couchés.

il y a des gens qui vous diront que les Expressions régulières ne devraient pas être récursives. Ils sont la limitation de vous. Ils ont besoin de vous soumettre, et ils le font en vous gardant dans l'ignorance.

Vous pouvez vivre dans leur réalité ou prendre la pilule rouge.

Comme Le Seigneur Marshal (est-il un parent du cours de Marshal. net?), J'ai vu la Underverse Pile en Fonction Regex Verset et revient avec pouvoirs les connaissances que vous ne pouvez pas imaginer. Oui, je pense qu'il y en avait un ou deux vieux qui les protégeaient, mais ils regardaient le football à la télé, donc ce n'était pas difficile.

je pense que le cas XML est assez simple. Le RegEx (dans la syntaxe. net), dégonflé et codé en base64 pour rendre plus facile à comprenez par votre esprit faible, devrait être quelque chose comme ceci:

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

les options à définir sont RegexOptions.ExplicitCapture . Le groupe de capture que vous recherchez est ELEMENTNAME . Si le groupe de capture ERROR n'est pas vide alors il y a eu une erreur d'analyse et le Regex s'est arrêté.

si vous avez des problèmes pour le reconvertir en une regex lisible par l'utilisateur, cela devrait vous aider:

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());
    }
}

si vous n'êtes pas sûr, Non, Je ne plaisante pas (mais peut-être que je suis allongé). Il VA travailler. J'ai construit des tonnes de tests unitaires pour le tester, et j'ai même utilisé (en partie) les tests de conformité . C'est un tokenizer, pas un analyseur complet, donc il ne divisera le XML que dans ses composants. Il ne va pas analyser / intégrer DTDs.

Oh... si vous voulez le code source du regex, avec quelques méthodes auxiliaires:

regex pour marquer un xml ou le plein

461
répondu xanatos 2017-10-18 07:26:13

dans shell, vous pouvez Parser HTML en utilisant:


(pourquoi vous ne devriez pas utiliser des regex match):

287
répondu kenorb 2017-05-23 12:34:53

je conviens que le bon outil pour analyser XML et en particulier HTML est un analyseur et non un moteur d'expression régulier. Cependant, comme d'autres l'ont souligné, l'utilisation d'un regex est parfois plus rapide, plus facile et permet de faire le travail si vous connaissez le format des données.

Microsoft a en fait une section de meilleures pratiques pour les Expressions régulières dans le cadre .NET et parle spécifiquement de envisager[ing] la source D'entrée .

les Expressions régulières ont des limites, mais avez-vous considéré ce qui suit?

le .net framework est unique en ce qui concerne les expressions régulières en ce qu'il supporte Balancing Group Definitions .

pour cette raison, je crois que vous pouvez analyser XML en utilisant des expressions régulières. Notez cependant, qu'il doit être valide XML ( les navigateurs sont très indulgents de HTML et permettent une mauvaise syntaxe XML à L'intérieur de HTML ). C'est possible puisque l'équilibre Définition du groupe" permettra au moteur d'expression régulier d'agir comme un PDA.

citation de l'article 1 cité ci-dessus:

.NET Moteur d'Expression Régulière

comme décrit ci-dessus, des constructions équilibrées ne peuvent être décrites par une expression régulière. Cependant, le moteur d'expression régulier. net fournit quelques constructions qui permettent équilibrée des constructions à reconnaître.

  • (?<group>) - pousse le résultat capturé sur la pile de capture avec le nom du groupe.
  • (?<-group>) - saute le plus haut de la capture avec le nom du groupe de l' la capture de la pile.
  • (?(group)yes|no) - correspond à la partie Oui s'il existe un groupe avec le groupe de noms ne correspond autrement aucune partie.

ces constructions permettent à une expression régulière .NET d'émuler un PDA restreint en permettant essentiellement des versions simples de la pile opérations: push, pop et vide. Les opérations simples sont assez équivalent à incrémenter, décrémenter et de les comparer à zéro respectivement. Cela permet au moteur d'expression régulière .NET de reconnaître un sous-ensemble de langues sans contexte, en particulier celles qui nécessite un compteur simple. Cela permet à son tour pour les non-traditionnels .net expressions régulières pour reconnaître l'individu correctement équilibré construire.

considérer l'expression régulière suivante:

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

utilisez les drapeaux:

  • Singleline
  • IgnorePatternWhitespace (pas nécessaire si vous vous effondrez regex et supprimer tous les blancs espace)
  • IgnoreCase (pas nécessaire)

Expression Régulière Expliqué (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

vous pouvez essayer ceci à un meilleur .net Regular Expression Tester .

j'ai utilisé la source de l'échantillon de:

<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>

C'trouvé le match:

   <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>

bien qu'il soit réellement sorti comme ceci:

<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>

enfin, j'ai vraiment apprécié L'article de Jeff Atwood: Parsing Html The Cthulhu Way . Assez drôle, il cite la réponse à cette question qui compte actuellement plus de 4k voix.

265
répondu Sam 2015-10-27 16:15:40

je suggère d'utiliser QueryPath pour analyser XML et HTML en PHP. C'est fondamentalement la même syntaxe que jQuery, seulement c'est du côté du serveur.

255
répondu John Fiala 2015-05-12 18:54:20

bien que les réponses que vous ne pouvez pas analyser HTML avec regexes soient correctes, elles ne s'appliquent pas ici. L'OP veut simplement analyser une balise HTML avec des regexes, et c'est quelque chose qui peut être fait avec une expression régulière.

L'a suggéré regex est mauvais, si:

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

si vous ajoutez quelque chose au regex, par rétractation il peut être forcé de correspondre à des choses stupides comme <a >> , [^/] est trop permissif. Notez également que <space>*[^/]* est redondant, car le [^/]* peut aussi correspondre à des espaces.

ma suggestion serait

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

(?<! ... ) est (dans les regexes Perl) le look négatif. Il lit "<, puis un mot, puis tout ce qui n'est pas un >, dont le dernier peut ne pas être une / suivie par >".

notez que cela permet des choses comme <a/ > (tout comme le regex original), donc si vous voulez quelque chose de plus restrictif, vous besoin de construire un regex pour apparier des paires d'attributs séparées par des espaces.

213
répondu moritz 2010-01-27 12:54:35

, Essayez:

<([^\s]+)(\s[^>]*?)?(?<!/)>

il est similaire au vôtre, mais le dernier > ne doit pas être après une barre oblique, et accepte également h1 .

178
répondu Kobi 2009-11-25 21:12:04

Sun Tzu, un ancien stratège Chinois, général, et philosophe, a dit:

il est dit que si vous connaissez vos ennemis et vous connaissez vous-même, vous pouvez gagner une centaine de batailles sans une seule perte. Si vous ne connaissez que vous-même, mais pas votre adversaire, vous pouvez gagner ou perdre. Si vous ne connaissez ni vous ni votre ennemi, vous vous mettrez toujours en danger.

dans ce cas votre ennemi est HTML et vous êtes soit vous-même ou à l'expression rationnelle. Vous pourriez même être Perl avec regex irrégulier. Connaître le langage HTML. Savez vous-même.

j'ai composé un haïku décrivant la nature de HTML.

HTML has
complexity exceeding
regular language.

j'ai aussi composé un haïku décrivant la nature du regex en Perl.

The regex you seek
is defined within the phrase
<([a-zA-Z]+)(?:[^>]*[^/]*)?>
167
répondu cytinus 2013-10-05 04:52:53
<?php
$selfClosing = explode(',', 'area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed');

$html = '
<p><a href="#">foo</a></p>
<hr/>
<br/>
<div>name</div>';

$dom = new DOMDocument();
$dom->loadHTML($html);
$els = $dom->getElementsByTagName('*');
foreach ( $els as $el ) {
    $nodeName = strtolower($el->nodeName);
    if ( !in_array( $nodeName, $selfClosing ) ) {
        var_dump( $nodeName );
    }
}

sortie:

string(4) "html"
string(4) "body"
string(1) "p"
string(1) "a"
string(3) "div"

définit simplement les noms des noeuds d'éléments qui se ferment d'eux-mêmes, charge toute la chaîne html dans une bibliothèque DOM, saisit tous les éléments, boucle et filtre ceux qui ne se ferment pas d'eux-mêmes et opère sur eux.

je suis sûr que vous savez déjà que vous ne devriez pas utiliser regex dans ce but.

154
répondu meder 2009-11-15 14:44:04

Je ne sais pas si vous en avez vraiment besoin, mais si vous utilisez aussi .NET, ne pouvez-vous pas utiliser Html Agility Pack ?

extrait:

c'est une bibliothèque de code .NET qui permet vous pour analyser" hors du web " HTML fichier. L'analyseur est très tolérant avec" real world " malformé HTML.

149
répondu GONeale 2009-11-16 23:15:03

vous voulez le premier > Non précédé d'un / . Regardez ici pour plus de détails sur la façon de faire cela. C'est ce que l'on appelle le lookbehind négatif.

cependant, une mise en œuvre naïve de ce qui finira par correspondre <bar/></foo> dans cet exemple de document

<foo><bar/></foo>

Pouvez-vous fournir un peu plus d'informations sur le problème que vous essayez de résoudre? Est-ce que vous itérez par le biais de tags de manière programmatique?

133
répondu Jherico 2012-03-19 15:04:25

le W3C explique l'analyse sous une forme pseudo regexp:

lien W3C

suivez les liens var pour QName , S , et Attribute pour obtenir une image plus claire.

Basé sur cela, vous pouvez créer un assez bon regexp pour gérer des choses comme les étiquettes de stripping.

122
répondu John-David Dalton 2014-05-16 14:43:57

si vous avez besoin de cela pour PHP:

le PHP DOM fonctions ne fonctionnera pas correctement à moins qu'il ne soit correctement formaté XML. Peu importe combien leur utilisation est meilleure pour le reste de l'humanité.

simplehtmldom est bon, mais je l'ai trouvé un peu buggy, et il est tout à fait mémoire lourd [se crash sur de grandes pages.]

Je n'ai jamais utilisé querypath , donc ne peut pas commenter sur son utilité.

un autre à essayer est mon DOMParser qui est très léger sur les ressources et je l'ai utilisé heureusement pendant un certain temps. Simple à apprendre et puissant.

pour Python et Java, des liens similaires ont été affichés.

pour les downvoters - Je n'ai écrit ma classe que lorsque les analyseurs XML se sont avérés incapables de résister à une utilisation réelle. La dévalorisation religieuse empêche juste des réponses utiles d'être affiché-gardez les choses dans la perspective de la question, s'il vous plaît.

105
répondu SamGoody 2012-03-19 15:02:18

j'ai utilisé un outil open source appelé HTMLParser avant. Il est conçu pour analyser HTML de différentes façons et sert assez bien le but. Il peut analyser HTML comme treenode différent et vous pouvez facilement utiliser son API pour obtenir des attributs hors du noeud. Vérifier et voir si cela peut vous aider.

90
répondu wen 2009-11-16 18:34:50

chaque fois que j'ai besoin d'extraire rapidement quelque chose d'un document HTML, J'utilise Tidy pour le convertir en XML, puis j'utilise XPath ou XSLT pour obtenir ce dont j'ai besoin. Dans votre cas, quelque chose comme ceci:

//p/a[@href='foo']
90
répondu Amal Murali 2014-04-04 08:11:06

Voici la solution:

<?php
// here's the pattern:
$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\4\s*)*\s*(\/>|>)/';

// a string to parse:
$string = 'Hello, try clicking <a href="#paragraph">here</a>
    <br/>and check out.<hr />
    <h2>title</h2>
    <a name ="paragraph" rel= "I\'m an anchor"></a>
    Fine, <span title=\'highlight the "punch"\'>thanks<span>.
    <div class = "clear"></div>
    <br>';

// let's get the occurrences:
preg_match_all($pattern, $string, $matches, PREG_PATTERN_ORDER);

// print the result:
print_r($matches[0]);
?>

pour le tester en profondeur, j'ai entré dans la chaîne des étiquettes à fermeture automatique comme:



  1. < br>

j'ai aussi entré des étiquettes avec:

  1. un attribut
  2. plus d'un attribut
  3. attributs dont la valeur est liée soit en apostrophes ou en "1519230920 des" guillemets
  4. attributs contenant des guillemets simples lorsque le délimiteur est une Guillemette double et vice versa
  5. "unpretty" attributs avec un espace avant le symbole"=", après qu'elle et à la fois avant et après.

si vous trouvez quelque chose qui ne fonctionne pas dans la validation de principe ci-dessus, je suis disponible en analysant le code pour améliorer mon compétence.

J'ai oublié que la question de l'utilisateur est d'éviter l'analyse de l'auto-balises de fermeture. Dans ce cas, le modèle est plus simple, se transformant en ceci:

$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\4\s*)*\s*>/';

l'utilisateur @ridgerunner a remarqué que le modèle ne permet pas attributs non référencés ou attributs sans valeur . Dans ce cas, un réglage fin nous apporte le motif suivant:

$pattern = '/<(\w+)(\s+(\w+)(\s*\=\s*(\'|"|)(.*?)\5\s*)?)*\s*>/';

< / EDIT>

Comprendre le motif

si quelqu'un est intéressé à en savoir plus sur le modèle, je fournis une certaine ligne:

  1. la première sous-expression (\w+) correspond au nom de la balise
  2. la deuxième sous-expression contient le motif d'un attribut. Il est composé par:
    1. un ou plusieurs espaces blancs \s +
    2. le nom de l'attribut (\w+)
    3. zéro ou plusieurs espaces \s* (il est possible ou non, en laissant des blancs ici)
    4. le symbole " = "
    5. encore une fois, zéro espace ou plus
    6. délimiteur de la valeur de l'attribut, simple ou double guillemet ('|"). Dans le motif, la citation unique est échappée car elle coïncide avec le délimiteur de chaîne PHP. Cette sous-expression est capturée avec les parenthèses pour qu'elle puisse être référencé à nouveau pour analyser la fermeture de l'attribut, c'est pourquoi il est très important.
    7. la valeur de l'attribut, égalée par presque n'importe quoi: (.*?); dans cette syntaxe spécifique, en utilisant le Greedy match (le point d'interrogation après l'astérisque) le moteur RegExp permet un opérateur de type"look-ahead", qui correspond à tout sauf ce qui suit cette sous-expression
    8. voici le plaisir: la partie \4 est un opérateur backreference , qui se réfère à une sous-expression définie auparavant dans le modèle, dans ce cas, je me réfère à la quatrième sous-expression, qui est le premier délimiteur d'attribut trouvé
    9. zéro ou plusieurs espaces \s*
    10. la sous-expression de l'attribut se termine ici, avec la spécification de zéro ou plus d'occurrences possibles, données par l'astérisque.
  3. puis, depuis un l'étiquette peut se terminer par un espace blanc avant le symbole">", zéro ou plusieurs espaces blancs sont assortis avec le \s* subpattern.
  4. la balise à apparier peut se terminer par un simple symbole">", ou une fermeture possible XHTML, qui utilise la barre oblique devant elle: (/>|>). La barre oblique est, bien sûr, échappée puisqu'elle coïncide avec le délimiteur de l'expression régulière.

petit conseil: pour mieux analyser ce code, il est nécessaire de regarder le code source généré depuis Je n'ai pas fourni de caractères spéciaux HTML échappant.

85
répondu Emanuele Del Grande 2017-10-18 07:33:46

j'aime analyser HTML avec des expressions régulières. Je ne cherche pas à analyser HTML idiot qui est délibérément cassé. Ce code est mon analyseur principal (Perl edition):

$_ = join "",<STDIN>; tr/\n\r \t/ /s; s/</\n</g; s/>/>\n/g; s/\n ?\n/\n/g;
s/^ ?\n//s; s/ $//s; print

cela s'appelle htmlsplit, divise le HTML en lignes, avec une étiquette ou un morceau de texte sur chaque ligne. Les lignes peuvent ensuite être traitées avec d'autres outils de texte et scripts, tels que grep , sed , Perl, etc. Je ne plaisante même pas :) Enjoy.

il est assez simple de réajuster mon script Slurp-everything-first Perl en une chose de streaming agréable, si vous souhaitez traiter d'énormes pages web. Mais ce n'est pas vraiment nécessaire.

je parie que je serai rétrogradé pour ça.

HTML Split


contre mon attente cela a suscité quelques critiques, donc je vais suggérer quelques meilleures expressions régulières:

/(<.*?>|[^<]+)\s*/g    # get tags and text
/(\w+)="(.*?)"/g       # get attibutes

ils sont bons pour XML / XHTML.

avec des variations mineures, il peut faire face au HTML désordonné... ou convertissez D'abord le HTML -> XHTML.


la meilleure façon d'écrire des expressions régulières est dans le style Lex / Yacc , pas en tant que monocouches opaques ou monstruosités à plusieurs lignes commentées. Je ne l'ai pas encore fait ici, ceux-là en ont à peine besoin.

84
répondu Sam Watkins 2014-11-18 16:15:09

voici un analyseur basé sur PHP qui analyse HTML en utilisant un certain regex ungodly. En tant qu'auteur de ce projet, je peux vous dire qu'il est possible de parser HTML avec regex, mais pas efficace. Si vous avez besoin d'une solution côté serveur (comme je l'ai fait pour mon plugin WordPress wp-Typography ), cela fonctionne.

73
répondu kingjeffrey 2010-07-18 02:52:04

il y a quelques regexes pour remplacer HTML avec BBCode ici . Pour tous les nonistes, notez qu'il n'essaie pas de pleinement analyser HTML, juste pour l'assainir. Il peut probablement se permettre de tuer des étiquettes que son simple "parser" ne peut pas comprendre.

par exemple:

$store =~ s/http:/http:\/\//gi;
$store =~ s/https:/https:\/\//gi;
$baseurl = $store;

if (!$query->param("ascii")) {
    $html =~ s/\s\s+/\n/gi;
    $html =~ s/<pre(.*?)>(.*?)<\/pre>/\[code]\[\/code]/sgmi;
}

$html =~ s/\n//gi;
$html =~ s/\r\r//gi;
$html =~ s/$baseurl//gi;
$html =~ s/<h[1-7](.*?)>(.*?)<\/h[1-7]>/\n\[b]\[\/b]\n/sgmi;
$html =~ s/<p>/\n\n/gi;
$html =~ s/<br(.*?)>/\n/gi;
$html =~ s/<textarea(.*?)>(.*?)<\/textarea>/\[code]\[\/code]/sgmi;
$html =~ s/<b>(.*?)<\/b>/\[b]\[\/b]/gi;
$html =~ s/<i>(.*?)<\/i>/\[i]\[\/i]/gi;
$html =~ s/<u>(.*?)<\/u>/\[u]\[\/u]/gi;
$html =~ s/<em>(.*?)<\/em>/\[i]\[\/i]/gi;
$html =~ s/<strong>(.*?)<\/strong>/\[b]\[\/b]/gi;
$html =~ s/<cite>(.*?)<\/cite>/\[i]\[\/i]/gi;
$html =~ s/<font color="(.*?)">(.*?)<\/font>/\[color=]\[\/color]/sgmi;
$html =~ s/<font color=(.*?)>(.*?)<\/font>/\[color=]\[\/color]/sgmi;
$html =~ s/<link(.*?)>//gi;
$html =~ s/<li(.*?)>(.*?)<\/li>/\[\*]/gi;
$html =~ s/<ul(.*?)>/\[list]/gi;
$html =~ s/<\/ul>/\[\/list]/gi;
$html =~ s/<div>/\n/gi;
$html =~ s/<\/div>/\n/gi;
$html =~ s/<td(.*?)>/ /gi;
$html =~ s/<tr(.*?)>/\n/gi;

$html =~ s/<img(.*?)src="(.*?)"(.*?)>/\[img]$baseurl\/\[\/img]/gi;
$html =~ s/<a(.*?)href="(.*?)"(.*?)>(.*?)<\/a>/\[url=$baseurl\/]\[\/url]/gi;
$html =~ s/\[url=$baseurl\/http:\/\/(.*?)](.*?)\[\/url]/\[url=http:\/\/]\[\/url]/gi;
$html =~ s/\[img]$baseurl\/http:\/\/(.*?)\[\/img]/\[img]http:\/\/\[\/img]/gi;

$html =~ s/<head>(.*?)<\/head>//sgmi;
$html =~ s/<object>(.*?)<\/object>//sgmi;
$html =~ s/<script(.*?)>(.*?)<\/script>//sgmi;
$html =~ s/<style(.*?)>(.*?)<\/style>//sgmi;
$html =~ s/<title>(.*?)<\/title>//sgmi;
$html =~ s/<!--(.*?)-->/\n/sgmi;

$html =~ s/\/\//\//gi;
$html =~ s/http:\//http:\/\//gi;
$html =~ s/https:\//https:\/\//gi;

$html =~ s/<(?:[^>'"]*|(['"]).*?)*>//gsi;
$html =~ s/\r\r//gi;
$html =~ s/\[img]\//\[img]/gi;
$html =~ s/\[url=\//\[url=/gi;
69
répondu kenorb 2015-05-19 16:20:44

à propos de la question des méthodes RegExp pour analyser (x)HTML, la réponse à tous ceux qui ont parlé de certaines limites est: vous n'avez pas été suffisamment formé pour contrôler la force de cette arme puissante, depuis personne ici a parlé de récursion .

un collègue de RegExp-agnostic m'a notifié cette discussion, qui n'est certainement pas la première sur le web à propos de ce vieux sujet brûlant.

après en lisant certains billets, la première chose que j'ai faite a été de chercher le "?R" chaîne dans ce fil. La seconde était de chercher à propos de "récursion".

Non, Sainte vache, aucune correspondance trouvée.

Comme personne n'a mentionné le mécanisme principal sur lequel un analyseur est construit, j'ai vite compris que personne n'avait compris.

si un analyseur (x)HTML a besoin de récursion, un analyseur RegExp sans récursion n'est pas suffisant. C'est une construction simple.

le art noir de RegExp est difficile à maîtriser , donc peut-être qu'il y a d'autres possibilités que nous avons laissées de côté en essayant et en testant notre solution personnelle pour capturer le web entier dans une main... Eh bien, j'en suis sûr:)

voici le motif magique:

$pattern = "/<([\w]+)([^>]*?)(([\s]*\/>)|(>((([^<]*?|<\!\-\-.*?\-\->)|(?R))*)<\/\1[\s]*>))/s";

essayez.

Il est écrit comme une chaîne de caractères PHP, donc le modificateur "s" permet aux classes d'inclure les nouvelles lignes.

Voici un exemple de note sur le manuel PHP j'ai écrit en janvier: référence

(attention, dans cette note j'ai mal utilisé le modificateur" m"; il doit être effacé, bien qu'il soit écarté par le moteur RegExp, puisqu'aucun ancrage n'a été utilisé).

Maintenant, on parle des limites de cette méthode d'un point de vue informé:

  1. selon la mise en œuvre spécifique du moteur RegExp, recursion peut avoir une limite dans le nombre de motifs imbriqués parsed , mais cela dépend du langage utilisé
  2. bien que corrompu (x)HTML ne conduit pas dans des erreurs graves, il n'est pas assaini .

de toute façon, ce n'est qu'un motif RegExp, mais il révèle la possibilité de développer de nombreuses implémentations puissantes.

J'ai écrit Ce modèle pour alimenter le Parser de descente récursive d'un moteur de modèle que j'ai construit dans mon cadre, et les performances sont vraiment grandes, à la fois dans les délais d'exécution ou dans l'utilisation de mémoire (rien à voir avec d'autres moteurs de modèle qui utilisent la même syntaxe).

66
répondu Emanuele Del Grande 2014-11-18 16:17:16

comme beaucoup de gens l'ont déjà souligné, HTML n'est pas un langage régulier qui peut le rendre très difficile à analyser. Ma solution c'est de le transformer en un langage régulier à l'aide d'un bon programme, puis utiliser un analyseur XML pour consommer les résultats. Il ya beaucoup de bonnes options pour cela. Mon programme est écrit en utilisant Java avec la bibliothèque jtidy pour transformer le HTML en XML puis Jaxen à xpath dans le résultat.

61
répondu Corey Sanders 2010-02-04 16:22:00
<\s*(\w+)[^/>]*>

les parties expliquées:

< : caractère de départ

\s* : il peut avoir des espaces avant le nom de l'étiquette (laid mais possible).

(\w+) : les étiquettes peuvent contenir des lettres et des chiffres (h1). Eh bien, \w correspond aussi à"_", mais ça ne fait pas mal je suppose. Si curieux utiliser ([A-zA-Z0-9]+) à la place.

[^/>]* : tout sauf > et / jusqu'à la fermeture >

> : fermeture >

sans lien

et à ceux qui sous-estiment les expressions régulières en disant qu'elles sont seulement aussi puissantes que les langues régulières:

un n ba n ba n qui n'est pas régulière et pas même sans contexte, peut être mis en correspondance avec ^(a+)bb$

Backreferencing FTW !

59
répondu daghan 2015-03-28 12:17:38

j'ai récemment écrit un désinfectant HTML en Java. Il est basé sur une approche mixte d'expressions régulières et de code Java. Personnellement je déteste les expressions régulières et sa folie (lisibilité, maintenabilité, etc.), mais si vous réduisez le champ de ses applications, il peut s'adapter à vos besoins. Quoi qu'il en soit, mon désinfectant utilise une liste blanche pour les balises HTML et une liste noire pour certains attributs de style.

pour votre commodité, j'ai mis en place un terrain de jeu pour que vous puissiez tester si le code correspond vos exigences: playground et Code Java . Vos commentaires seront appréciés.

il y a un petit article décrivant ce travail sur mon blog: http://roberto.open-lab.com

55
répondu 3 revs, 3 users 64%Roberto 2013-12-16 22:19:22

Il me semble que vous essayez de faire correspondre les balises sans un "/" à la fin. Essayez ceci:

<([a-zA-Z][a-zA-Z0-9]*)[^>]*(?<!/)>
52
répondu manixrock 2009-11-15 17:13:19

si vous essayez simplement de trouver ces étiquettes (sans ambitions d'analyse) essayez cette expression régulière:

/<[^/]*?>/g

Je l'ai écrit en 30 secondes, et testé ici: http://gskinner.com/RegExr /

il correspond aux types de tags que vous avez mentionnés, tout en ignorant les types que vous avez dit que vous vouliez ignorer.

50
répondu Lonnie Best 2016-05-31 07:23:30

bien qu'il ne soit pas approprié et efficace d'utiliser des expressions régulières dans ce but, il arrive que des expressions régulières fournissent des solutions rapides pour des problèmes d'allumettes simples et, à mon avis, ce n'est pas une horreur d'utiliser des expressions régulières pour des travaux insignifiants.

Il y a un définitive blog sur la correspondance intime des éléments HTML écrit par Steven Levithan.

48
répondu Emre Yazici 2010-02-09 03:59:27