Pouvez-vous fournir des exemples des raisons pour lesquelles il est difficile d'analyser XML et HTML avec une expression régulière? [fermé]

402

Une erreur que je vois des gens faire encore et encore est d'essayer 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 cela est valide:

<tag
attr="5"
/>

Les gens veulent traiter <ou <tag comme le début d'un tag, mais des trucs comme celui-ci existent à l'état sauvage:

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

Les gens veulent souvent faire correspondre les balises de début aux balises de fin, mais XML et HTML permettent aux balises de se contenir (que les expressions régulières 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 balisées (même si elles semblent être normales lors de leur affichage):

<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 mal formatées ou incomplètes:

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

De quels autres accrochages êtes-vous au courant?

Chas. Owens
la source
14
Les navigateurs Web donnent un sens à ce genre de gâchis des millions de fois par seconde, quelqu'un ne peut-il pas créer une classe d'analyse de page Web pour nous, simples mortels?
Jon Winstanley
24
Jon, ils l'ont fait. En Perl il y a beaucoup de HTML :: Parser, HTML :: TreeBuilder, etc. Il y en a presque certainement un pour votre jauge.
Chas. Owens
12
La meilleure réponse est, stackoverflow.com/a/1732454/135078 (Attention Zalgo)
Kelly S. French
3
Il y a une bonne explication pourquoi [vous ne pouvez pas analyser [X] HTML avec regex] [1] [1]: stackoverflow.com/a/1732454/468725
Pavel P
4
Voici une bonne explication de la façon dont vous pouvez certainement analyser HTML avec des modèles , ainsi que pourquoi vous ne souhaitez probablement pas le faire.
tchrist

Réponses:

260

Voici du 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 du HTML valide:

<!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 toute l'analyse spécifique au navigateur pour les constructions invalides.

Bonne chance opposant regex à cela!

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

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd"> 
<HTML/
  <HEAD/
    <TITLE/>/
    <P/>
bobince
la source
6
Celui XML? Il existe plusieurs constructions différentes, ce qui est gênant? Le sous-ensemble interne DTD? C'est définir un nouveau & entity; appelé 'y', contenant une séquence ']>' qui normalement, sinon entre guillemets, mettra fin au sous-ensemble interne.
bobince
16
(Cela démontre que vous devez avoir une connaissance assez approfondie de certaines des fonctionnalités DTD les plus ésotériques et archaïques de XML pour analyser correctement un document, même si vous n'êtes pas un analyseur validant la DTD.)
bobince
17
Les exemples HTML utilisent une fonctionnalité rarement connue: les raccourcis. En savoir plus sur w3.org/QA/2007/10/shorttags.html
netvope
25
Chaque fois que quelqu'un écrit du HTML comme indiqué ci-dessus, Tim Berners-Lee verse une seule larme.
fgysin réintègre Monica le
5
J'adore la façon dont le surligneur Syntax de Stackoverflow échoue lors de la 1ère occurrence de "]".
GlassGhost
71

Réellement

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

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

Ce n'est pas du XML valide car les «<» et «>» ne sont pas des caractères valides dans les chaînes d'attributs. Ils doivent être échappés à l'aide des entités XML correspondantes & lt; et & gt;

Ce n'est pas non plus du HTML valide car le court formulaire de fermeture 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 sa fermeture manuelle est en fait incorrecte et équivaut à la fermeture de toute autre balise deux fois.

La bonne version 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 non plus du HTML ou du XML valide. 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 plus amusante: vous pouvez réellement choisir d'utiliser "ou 'comme caractère de citation de votre 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 plus gros problème avec l'analyse HTML est que les gens ne comprennent généralement pas correctement toutes les règles de syntaxe. Le fait que votre navigateur interprète votre groupe de balises comme HTML ne signifie pas que vous avez réellement écrit du HTML valide.

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

Fondamentalement, XML n'est pas conçu pour être analysé avec des expressions rationnelles. Mais il n'y a également aucune raison de le faire. Il existe de 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 avec une expression rationnelle et vous pouvez ensuite utiliser des technologies intéressantes comme XPath ou XSLT sur l'arborescence DOM résultante.

Ma réponse est donc: non seulement l'analyse de XML avec des expressions régulières 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 tout simplement trop difficile pour même essayer d'analyser par vous-même. Premièrement, la syntaxe légale a de nombreuses petites subtilités que vous ne connaissez peut-être pas, et deuxièmement, le HTML à l'état sauvage n'est qu'une énorme pile puante (vous obtenez ma dérive). Il existe une variété de bibliothèques d'analyseurs laxistes qui font un bon travail pour gérer le HTML comme la soupe de balises, utilisez-les simplement.

LordOfThePigs
la source
8
Vous n'avez pas besoin de vous échapper> comme>.
Joey
8
D'accord, s / valid / existe dans la nature / g
Chas. Owens
1
En fait, selon la spécification, vous devez échapper> comme> tout comme vous devez échapper <comme <& & & amp; et dans les attributs "as" et "as & apos; c'est juste que beaucoup d'analyseurs
LordOfThePigs
19
La spécification ne dit pas que '>' doit être échappé - sauf pour le cas spécial de la séquence ']]>' dans le contenu. Pour cette raison, il est plus facile de toujours échapper '>', mais ce n'est pas requis par spec.
bobince
8
>signe est parfaitement valide dans html stackoverflow.com/questions/94528/…
jfs
56

J'ai écrit une entrée de blog entière sur ce sujet: Limitations des expressions régulières

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

Le paragraphe précédent est accompagné d'une légère mise en garde. Certaines implémentations d'expressions régulières supportent désormais l'idée de récursivité. Cependant, une fois que vous commencez à ajouter la récursivité dans vos expressions regex, vous étirez vraiment les limites et devez envisager un analyseur.

JaredPar
la source
20

Un problème qui ne figure pas dans votre liste est que les attributs peuvent apparaître dans n'importe quel ordre, donc si votre expression régulière recherche un lien avec le href "foo" et la classe "bar", ils peuvent venir dans n'importe quel ordre, et avoir un certain nombre d'autres les choses entre eux.

AmbroseChapel
la source
Ah, oui, c'est même la question qui m'a poussé à poser celle-ci (le premier lien).
Chas. Owens
16

Cela dépend de ce que vous entendez par "analyse". D'une manière générale, XML ne peut pas être analysé à l'aide de l'expression rationnelle car la grammaire XML n'est en aucun cas régulière. Pour le dire simplement, les expressions régulières ne peuvent pas compter (enfin, les expressions régulières Perl pourraient en fait être capables de compter les choses), vous ne pouvez donc pas équilibrer les balises d'ouverture-fermeture.

Anton Gogolev
la source
je suppose que les références peuvent résoudre le problème des balises d'ouverture et de fermeture
Rishul Matta
1
@RishulMatta: comment? Vous avez seulement un nombre limité de références et notez que vous devez inverser les balises ... De plus, la définition stricte des expressions régulières ne permet pas les références.
Willem Van Onsem
.NET permet d'équilibrer les expressions, qui apparaissent et poussent, et pourrait théoriquement être utilisé pour faire correspondre la hiérarchie. Mais c'est toujours une mauvaise idée.
Abel
9

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

Je suis tout à fait d'accord que l'analyse de html et xml à l'aide d'une expression régulière n'est pas possible car d'autres personnes ont 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 qu'une expression régulière ou même une "sous-chaîne" encore plus simple est suffisante.

Robin Day
la source
7
Définissez «assez bien». Inévitablement, la simple expression régulière ne fonctionnera pas. Ne correspond pas à quelque chose ou ne correspond pas à quelque chose que vous ne devriez pas un bug? Si c'est le cas, l'utilisation des expressions rationnelles est une erreur. Les analyseurs HTML et XML ne sont pas difficiles à utiliser. Éviter de les apprendre est une fausse économie.
Chas. Owens
1
ok, définissez "assez bien". Disons que j'ai une page Web qui me dit l'adresse IP du client. C'est tout. Maintenant, je dois écrire une application pour la machine client qui me donne son adresse IP. Je vais sur ce site, je cherche une adresse IP et je la renvoie. L'analyse du HTML n'est pas nécessaire!
Robin Day
2
Si vous avez une chaîne arbitraire dont le format est entièrement sous votre contrôle, le fait que la chaîne se trouve être du XML bien formé n'est vraiment pas pertinent. Mais presque aucun cas d'utilisation pour XML ne tombe dans cette catégorie.
Robert Rossney
15
Je peux vous dire par expérience douloureuse que la plupart du temps, il est possible d'obtenir ce que vous voulez en utilisant des schémas de regex complexes absurdes. Jusqu'à ce que le site Web subisse un petit changement hilarant et vous pouvez jeter cette expression régulière qui vous a fait pleurer pendant deux jours par la fenêtre et recommencer à nouveau.
Thomasz
@Robert: "presque aucun cas d'utilisation" est une exagération. D'après mon expérience, il existe des cas d'utilisation assez courants. YAGNI s'applique ici ... parfois. L'astuce consiste à savoir à quel point votre solution doit être à l'épreuve des balles et durable, pour la tâche particulière à laquelle vous vous adressez. Robin a un bon point. Il dit seulement que l'analyse syntaxique XML complète n'en vaut pas toujours la peine ... ce qui est vrai même si vous savez comment l'utiliser.
LarsH
6

Normalement, les gens écrivent par défaut des schémas gourmands, ce qui conduit souvent à un fichier non réfléchi. * Transformant de gros morceaux de fichier en <foo>. * </foo>.

le chaos
la source
2
En plus de rendre la répétition paresseuse .*?<, vous pouvez résoudre ce problème en utilisant une classe de caractères négative comme [^<]*<. (Avertissement: évidemment ce n'est toujours pas infaillible, ce qui est le point de la question.)
Rory O'Kane
6

Je suis tenté de dire "ne réinventez pas la roue". Sauf que XML est un format vraiment très 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 comment utiliser les 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 économiserez en n'ayant pas à apprendre à utiliser une bibliothèque d'analyse XML sera plus que compensé par la quantité de travail créatif et de correction de bogues que vous devrez faire. Pour vous, google "bibliothèque XML" et tirez parti du travail de quelqu'un d'autre.

Isaac Rabinovitch
la source
3
Ce n'est pas aussi complexe que C ++.
Cole Johnson
6
@Cole "Cole9" Johnson Je n'utiliserais pas non plus les RE pour analyser C ++.
Isaac Rabinovitch
2
Si XML est un synchrotron, C ++ serait le Large Hadron Collider.
Kevin Kostlan
4

Je crois que ce classique contient les informations que vous recherchez. Vous pouvez trouver le point dans l'un des commentaires:

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

Quelques informations supplémentaires sur Wikipédia: Chomsky Hierarchy

Adam Arold
la source
6
«Expression régulière» n'a pas exactement la même signification dans les discussions formelles de grammaire qu'ici. La plupart des moteurs regex existants sont plus puissants que les grammaires Chomsky Type 3 (par exemple, correspondance non gourmande, backrefs). Certains moteurs regex (tels que Perl) sont Turing complet. Il est vrai que même ceux-ci sont de mauvais outils pour analyser HTML, mais cet argument souvent cité n'est pas la raison.
dubiousjim
4

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

  1. L'expression régulière est presque toujours incorrecte. Il existe des entrées légitimes auxquelles il ne correspondra pas 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 choses étranges que XML permet 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 la seule entrée qui cassera votre application.

  3. Si l'expression régulière est suffisamment correcte pour couvrir 99,99% des cas, elle sera complètement illisible et impossible à maintenir.

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

Michael Kay
la source
1

D'une manière générale, XML ne peut pas être analysé à l'aide de l'expression rationnelle car la grammaire XML n'est en aucun cas régulière. Pour le dire simplement, les expressions régulières ne peuvent pas compter (enfin, les expressions régulières Perl pourraient en fait être capables de compter les choses), vous ne pouvez donc pas équilibrer les balises d'ouverture-fermeture.

Je ne suis pas d'accord. Si vous utilisez récursif dans regex, vous pouvez facilement trouver des balises d'ouverture et de fermeture.

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

Maxim Suslov
la source
Tout d'abord, les expressions rationnelles récursives ne sont pas des expressions régulières (si vous regardez entre parenthèses, vous verrez que je concède que les expressions rationnelles de Perl, qui sont récursives, peuvent compter des choses, ce qui est nécessaire pour gérer le HTML). Deuxièmement, votre exemple est pour XHTML ou XML qui est bien formé. HTML n'est pas bien formé. Troisièmement, vous devez vous demander s'il est plus facile d'étendre et de maintenir un analyseur écrit dans un langage regex récursif ou un langage de programmation à usage général.
Chas. Owens
Quatrièmement, même votre exemple est trivialement cassé tout en étant XML valide. Ajoutez un espace entre content_block et id et il échoue. Je suis certain que si je passais quelques minutes de plus, je trouverais une autre erreur structurelle dans votre code. Ce n'est tout simplement pas une bonne idée.
Chas. Owens
1

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

Erutan409
la source