web-dev-qa-db-fra.com

Pouvez-vous donner quelques exemples de pourquoi il est difficile d'analyser XML et HTML avec une expression régulière?

Une erreur que je vois que les gens font over et over again essaie d'analyser XML ou HTML avec une expression régulière. Voici quelques raisons pour lesquelles analyser XML et HTML est difficile:

Les gens veulent traiter un fichier comme une séquence de lignes, mais ceci est valable:

<tag
attr="5"
/>

Les gens veulent traiter les balises <ou <comme le début d'une balise, mais ce genre de choses existe à l'état sauvage:

<img src="imgtag.gif" alt="<img>" />

Les gens veulent souvent faire correspondre les balises de départ aux balises de fin, mais XML et HTML permettent aux balises de se contenir (ce que les expressions rationnelles traditionnelles ne peuvent pas gérer du tout):

<span id="outer"><span id="inner">foo</span></span> 

Les gens veulent souvent faire correspondre le contenu d'un document (comme le fameux problème "Trouver tous les numéros de téléphone sur une page donnée"), mais les données peuvent être marquées (même si elles semblent normales):

<span class="phonenum">(<span class="area code">703</span>)
<span class="prefix">348</span>-<span class="linenum">3020</span></span>

Les commentaires peuvent contenir des balises incomplètes ou mal formatées:

<a href="foo">foo</a>
<!-- FIXME:
    <a href="
-->
<a href="bar">bar</a>

Quels autres pièges êtes-vous au courant?

393
Chas. Owens

Voici un code XML valide et amusant pour vous:

<!DOCTYPE x [ <!ENTITY y "a]>b"> ]>
<x>
    <a b="&y;>" />
    <![CDATA[[a>b <a>b <a]]>
    <?x <a> <!-- <b> ?> c --> d
</x>

Et ce petit paquet de joie est valide HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" [
    <!ENTITY % e "href='hello'">
    <!ENTITY e "<a %e;>">
]>
    <title>x</TITLE>
</head>
    <p id  =  a:b center>
    <span / hello </span>
    &amp<br left>
    <!---- >t<!---> < -->
    &e link </a>
</body>

Sans parler de toutes les analyses spécifiques au navigateur pour les constructions non valides.

Bonne chance, opposant regex à cela!

EDIT (Jörg W Mittag): Voici un autre joli morceau de HTML 4.01 valide et bien formé:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd"> 
<HTML/
  <HEAD/
    <TITLE/>/
    <P/>
259
bobince

Réellement

<img src="imgtag.gif" alt="<img>" />

n'est pas valide HTML et n'est pas valide XML non plus.

Il ne s'agit pas d'un code XML valide, car '<' et '>' ne sont pas des caractères valides dans les chaînes d'attributs. Ils doivent être échappés en utilisant les entités XML correspondantes lt; et gt;

Il ne s'agit pas non plus d'un code HTML valide, car le formulaire de fermeture abrégé n'est pas autorisé en HTML (mais est correct en XML et XHTML). La balise 'img' est également une balise implicitement fermée selon la spécification HTML 4.01. Cela signifie que la fermeture manuelle est en fait une erreur et équivaut à fermer deux fois une autre balise.

La version correcte en HTML est

<img src="imgtag.gif" alt="&lt;img&gt;">

et la version correcte en XHTML et XML est

<img src="imgtag.gif" alt="&lt;img&gt;"/>

L'exemple suivant que vous avez donné est également invalide

<
tag
attr="5"
/>

Ce n'est pas valide HTML ou XML non plus. Le nom de la balise doit être juste derrière le '<', bien que les attributs et la fermeture '>' puissent être où ils veulent. Donc, le XML valide est en fait

<tag
attr="5"
/>

Et voici une autre option plus amusante: vous pouvez choisir d'utiliser "ou" comme caractère de citation d'attribut.

<img src="image.gif" alt='This is single quoted AND valid!'>

Toutes les autres raisons qui ont été publiées sont correctes, mais le principal problème de l'analyse HTML est que les utilisateurs ne comprennent généralement pas correctement toutes les règles de syntaxe. Le fait que votre navigateur interprète votre groupe de balises en tant que HTML ne signifie pas que vous avez réellement écrit du code HTML valide.

Edit: Et même stackoverflow.com est d’accord avec moi sur la définition de valide et invalide. Votre XML/HTML non valide n'est pas mis en surbrillance, alors que ma version corrigée l'est.

Fondamentalement, XML n'est pas conçu pour être analysé avec les expressions rationnelles. Mais il n'y a également aucune raison de le faire. Il existe de très nombreux analyseurs XML pour chaque langue. Vous avez le choix entre les analyseurs SAX, les analyseurs DOM et les analyseurs Pull. Tous ces éléments sont garantis beaucoup plus rapides que l'analyse syntaxique et vous pouvez ensuite utiliser des technologies intéressantes telles que XPath ou XSLT sur l'arborescence DOM résultante.

Ma réponse est donc: non seulement l’analyse XML avec regexps est difficile, mais c’est aussi une mauvaise idée. Utilisez simplement l’un des millions d’analyseurs XML existants et profitez de toutes les fonctionnalités avancées de XML.

Le HTML est trop difficile pour même essayer d’analyser vous-même. Premièrement, la syntaxe légale comporte de nombreuses petites subtilités dont vous n'êtes peut-être pas au courant, et deuxièmement, le langage HTML à l'état sauvage n'est qu'un énorme tas puant de (vous avez ma dérive). Il existe une variété de bibliothèques d'analyseurs laxistes qui gèrent très bien le langage HTML, comme les balises de balises, utilisez-les simplement.

68
LordOfThePigs

J'ai écrit une entrée de blog complète à ce sujet: Limitations des expressions régulières

Le nœud du problème réside dans le fait que HTML et XML sont des structures récursives qui nécessitent des mécanismes de comptage afin de pouvoir les analyser correctement. Une vraie regex n'est pas capable de compter. Vous devez avoir une grammaire sans contexte pour pouvoir compter.

Le paragraphe précédent vient avec une légère mise en garde. Certaines implémentations de regex supportent maintenant l'idée de récursion. Cependant, une fois que vous avez commencé à ajouter de la récursivité dans vos expressions regex, vous étendez vraiment les limites et vous devriez envisager un analyseur syntaxique.

56
JaredPar

Un attribut qui ne se trouve pas sur votre liste est que les attributs peuvent apparaître dans n’importe quel ordre. Par conséquent, si votre regex recherche un lien avec le href "foo" et la classe "bar", ils peuvent apparaître dans n’importe quel ordre et avoir un nombre quelconque d’autres. les choses entre eux.

20
AmbroseChapel

Cela dépend de ce que vous entendez par "analyser". De manière générale, XML ne peut pas être analysé avec regex car la grammaire XML n’est en aucun cas régulière. Pour le dire simplement, les expressions rationnelles ne peuvent pas compter (eh bien, les expressions rationnelles Perl pourraient en réalité compter les choses), de sorte que vous ne pouvez pas équilibrer les balises open-close.

16
Anton Gogolev

Est-ce que les gens font une erreur en utilisant une expression régulière, ou est-ce simplement suffisant pour la tâche qu'ils tentent d'accomplir?

Je suis tout à fait d’accord pour dire qu’il n’est pas possible d’analyser le HTML et le XML à l’aide d’une expression rationnelle, car d’autres personnes ont déjà répondu.

Cependant, si votre exigence n'est pas d'analyser html/xml mais simplement d'obtenir un petit bit de données dans un bit "bien connu" de html/xml, alors peut-être une expression régulière ou même une "sous-chaîne" encore plus simple.

9
Robin Day

Les gens écrivent normalement par défaut en écrivant des motifs gourmands, ce qui conduit assez souvent à un fichier non pensé. * Insufflant de gros morceaux de fichier dans le plus grand <foo>. * </ Foo>.

6
chaos

Je suis tenté de dire "ne réinventez pas la roue". Sauf que XML est un format vraiment, vraiment complexe. Alors peut-être devrais-je dire "ne réinventez pas le synchrotron".

Peut-être que le bon cliché commence "quand tout ce que vous avez est un marteau ..." Vous savez utiliser des expressions régulières, les expressions régulières sont bonnes pour l'analyse, alors pourquoi se donner la peine d'apprendre une bibliothèque d'analyse XML?

Parce que l’analyse XML est difficile. Tout effort que vous épargnerez en évitant d'apprendre à utiliser une bibliothèque d'analyse XML sera plus que compensé par la quantité de travail créatif et de résolution de bugs que vous devrez faire. Dans votre intérêt, recherchez "bibliothèque XML" dans Google et exploitez le travail de quelqu'un d'autre.

6
Isaac Rabinovitch

Je pense que les problèmes se résument à:

  1. La regex est presque toujours incorrecte. Il y a des entrées légitimes auxquelles il ne pourra pas correspondre correctement. Si vous travaillez assez dur, vous pouvez le rendre correct à 99%, ou à 99,999%, mais le rendre correct à 100% est presque impossible, ne serait-ce qu'en raison des étranges propriétés permises par XML en utilisant des entités.

  2. Si l'expression régulière est incorrecte, même pour 0,00001% des entrées, vous avez un problème de sécurité, car quelqu'un peut découvrir l'entrée qui rompra votre application.

  3. Si le regex est suffisamment correct pour couvrir 99,99% des cas, il sera complètement illisible et incontrôlable.

  4. Il est très probable qu'une expression régulière se comporte très mal avec des fichiers d'entrée de taille moyenne. Ma toute première rencontre avec XML a été de remplacer un script Perl qui analysait (de manière incorrecte) les documents XML entrants avec un analyseur XML approprié. Nous avons non seulement remplacé 300 lignes de code illisible par 100 lignes que tout le monde pouvait comprendre, mais nous avons également amélioré le temps de réponse de l'utilisateur. de 10 secondes à environ 0,1 seconde.

4
Michael Kay

Je crois que this classique possède les informations que vous recherchez. Vous pouvez trouver le point dans l'un des commentaires ici:

Je pense que la faille ici est que HTML est une grammaire de Chomsky Type 2 (grammaire libre de contexte) et RegEx est une grammaire de Chomsky Type 3 (expression régulière). Étant donné qu'une grammaire de type 2 est fondamentalement plus complexe qu'une grammaire de type 3 - vous ne pouvez pas espérer réussir cela . Mais beaucoup essaieront, certains revendiqueront le succès et d’autres trouveront la faute et vous gâcheront totalement.

Quelques informations supplémentaires sur Wikipedia: Hiérarchie de Chomsky

4
Adam Arold

J'ai donné une réponse simplifiée à ce problème ici . Bien que cela ne représente pas la note de 100%, j'explique comment il est possible si vous êtes prêt à effectuer un travail de pré-traitement.

1
Erutan409

De manière générale, XML ne peut pas être analysé avec regex car la grammaire XML n’est en aucun cas régulière. Pour le dire simplement, les expressions rationnelles ne peuvent pas compter (eh bien, les expressions rationnelles Perl pourraient en réalité compter les choses), de sorte que vous ne pouvez pas équilibrer les balises open-close.

Je ne suis pas d'accord. Si vous allez utiliser récursif dans regex, vous pouvez facilement trouver les balises open et close.

Ici J'ai montré un exemple de regex pour éviter les erreurs d'analyse des exemples dans le premier message.

1
Maxim Suslov