OVH Cloud OVH Cloud

Supression des balise HTML (expression reguliere)

22 réponses
Avatar
JB. Deschampheleire
Bonjour, j'aimerais supprimer toutes les balises HTML d'un texte (cad les
chaines du type <xxx>) mais il me supprime trop... c assez bizare et pourtant
l'expression reguilere que j'utilise me semble juste... la voici:

string resultat = Regex.Replace(input,"<.*[^<]>","");

j'ai l'impression que si on a qqch du type "<TAG1> hello <TAG2>"... il prend
tout alors qu'il devrai seulement prendre <TAG1> et <TAG2>... je ne comprend
pas pq... qqn pourrait me donner la bonne expression a utiliser pour
supprimer SEULEMENT les balise (et donc, qu'il ne reste plus que le "hello")
Merci d'avance

10 réponses

1 2 3
Avatar
Patrick Philippot
JB. Deschampheleire wrote:
Bonjour, j'aimerais supprimer toutes les balises HTML d'un texte (cad
les chaines du type <xxx>) mais il me supprime trop... c assez bizare
et pourtant l'expression reguilere que j'utilise me semble juste...
la voici:

string resultat = Regex.Replace(input,"<.*[^<]>","");

j'ai l'impression que si on a qqch du type "<TAG1> hello <TAG2>"...
il prend tout alors qu'il devrai seulement prendre <TAG1> et
<TAG2>... je ne comprend pas pq... qqn pourrait me donner la bonne
expression a utiliser pour supprimer SEULEMENT les balise (et donc,
qu'il ne reste plus que le "hello") Merci d'avance



Bonjour,

Votre expression n'est pas correcte. Par défaut, les expressions
régulières utilise le "greedy matching" ou "longest match". RegEx essaie
de trouver la chaîne la plus longue correspondant au pattern. Dans votre
expression vous spécifiez que le dernier caractère avant le > ne doit
pas être <. Donc l'ensemble de la chaîne "<TAG1> hello <TAG2>"
correspond. Vous dîtes expressément, si j'ose dire :-), que entre le <
et le > il peut y avoir n'importe quel caractère de 0 à n fois (.*) et
ensuite un caractère qui ne doit pas être <. ce qui décrit parfaitement
"<TAG1> hello <TAG2>" dans sa totalité, le dernier caractère avant le >
de <TAG2> étant 2 et pas <.

La bonne expression est donc
"<[^<]*>"

Par ailleurs, si vous avez besoin d'éviter le "greedy matching" et de
passer en mode "lazy matching" (shortest match), il vous suffit de
mettre un ? derrière le quantificateur. Voir la doc.

Pour vous familiariser avec les expressions régulières, je ne saurais
trop vous conseiller les outils Expresso (http://www.ultrapico.com/) et
The Regulator
(http://weblogs.asp.net/rosherove/archive/2004/04/20/117069.aspx).

ainsi que ce tutorial

http://www.codetools.com/useritems/RegexTutorial.asp

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Ambassadeur Kosh
je dirais xsl : suffit juste de selectionner les noeuds text().
sinon, à coup de regex, voir Patrick.
Avatar
Patrick Philippot
Ambassadeur Kosh wrote:
je dirais xsl : suffit juste de selectionner les noeuds text().
sinon, à coup de regex, voir Patrick.



C'est une bonne idée mais une transformation XSL suppose que l'on part
d'un document HTML "bien-formé", ce qui est trop rarement le cas. Ne
serait-ce qu'à cause des balises <P> par exemple, que l'on ferme ou non,
selon son bon plaisir.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
Simon Mourier [MS]
Une solution possible consiste à utiliser un outil qui parse le HTML et
présente un modèle objet similaire à XML, avec support de XPATH, XSL, etc...
Disponible ici:

.NET Html Agility Pack: How to use malformed HTML just like it was
well-formed XML...
http://blogs.msdn.com/smourier/archive/2003/06/04/8265.aspx

Simon.

"Patrick Philippot" a écrit dans le
message de news: %
Ambassadeur Kosh wrote:
je dirais xsl : suffit juste de selectionner les noeuds text().
sinon, à coup de regex, voir Patrick.



C'est une bonne idée mais une transformation XSL suppose que l'on part
d'un document HTML "bien-formé", ce qui est trop rarement le cas. Ne
serait-ce qu'à cause des balises <P> par exemple, que l'on ferme ou non,
selon son bon plaisir.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr



Avatar
JB. Deschampheleire
La 1ere reponse de Patrick me convenait tout a fait..... finnalement
l'expression n'etait pas fort eloignee de la mienne.. fallit juste que je
retire le "." et mette le[^<] devant... a ce propos, je n'ai pas vraiment
compris pq (pour les deux)... sauriez vous m'expliqez en deux mots ?
- retirer le "." :
- mette le[^<] devant:
merci pour votre aide...

"Simon Mourier [MS]" a écrit :

Une solution possible consiste à utiliser un outil qui parse le HTML et
présente un modèle objet similaire à XML, avec support de XPATH, XSL, etc...
Disponible ici:

..NET Html Agility Pack: How to use malformed HTML just like it was
well-formed XML...
http://blogs.msdn.com/smourier/archive/2003/06/04/8265.aspx

Simon.

"Patrick Philippot" a écrit dans le
message de news: %
> Ambassadeur Kosh wrote:
>> je dirais xsl : suffit juste de selectionner les noeuds text().
>> sinon, à coup de regex, voir Patrick.
>
> C'est une bonne idée mais une transformation XSL suppose que l'on part
> d'un document HTML "bien-formé", ce qui est trop rarement le cas. Ne
> serait-ce qu'à cause des balises <P> par exemple, que l'on ferme ou non,
> selon son bon plaisir.
>
> --
> Patrick Philippot - Microsoft MVP
> MainSoft Consulting Services
> www.mainsoft.fr
>





Avatar
Patrick Philippot
JB. Deschampheleire wrote:
La 1ere reponse de Patrick me convenait tout a fait..... finnalement
l'expression n'etait pas fort eloignee de la mienne.. fallit juste
que je retire le "." et mette le[^<] devant... a ce propos, je n'ai
pas vraiment compris pq (pour les deux)... sauriez vous m'expliqez en
deux mots ?
- retirer le "." :
- mette le[^<] devant:



Bonjour et bonne année.

Il est plus facile d'expliquer la validité d'une expression correcte que
pourquoi l'expression originale ne l'est pas. Bon, malgré les brumes non
dissipées d'une veillée prolongée (quoique fort modérée côté libations),
je vais tenter la chose...

"<.*[^<]>" signifie

- toute chaîne commençant par <
- lui-même suivi d'une séquence de 0 à n caractères quelconques : .*
- séquence nécessairement suivie d'un caractère autre que "<" : [^<]
- et terminée par >

Étant donné que j'ai déjà expliqué que par défaut, le système essaie de
trouver la chaîne la plus longue correspondant au pattern, la séquence
"<TAG1> hello <TAG2>" va être prise en priorité de préférence à <TAG1>:
"TAG1> hello <TAG" est bien une séquence de 0 à n caractères quelconques
et "2" est bien différent de "<". Dans ce cas, l'expression régulière
est analysée comme suit:

< ===> <
TAG1> hello <TAG ===> .*
2 ===> [^<]
===> >



Le . (caractère quelconque) implique que vous acceptez "<" comme élément
valide de la séquence ".*".

"[^<]>" indique que vous n'excluez le "<" que lorsqu'il se trouve juste
devant le ">", ce qui n'a pas vraiment de sens.

L'expression que je vous ai proposée est plus simple:

- toute chaîne commençant par <
- lui-même suivi d'une séquence de 0 à n caractères quelconques mais
différent de "<" : ([^<]*)
- et terminée par >

Ce qui implique automatiquement un match court puisque l'on ne peut pas
inclure un autre début de balise.

Votre question me fait douter d'une chose: avez vous bien compris que
les quantificateurs (*, +,...) s'appliquent à l'expression qui précède
et non pas à ce qui suit le quantificateur?

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
merci pour ces specifications supplementaires... :)
a bientot
Avatar
Zazar
Bonsoir,

La bonne expression est donc
"<[^<]*>"



Personnellement, je l'aurais plutôt écrit :
"<[^>]*>"
ca me paraît plus logique.

Sinon, cette expression ne marche pas dans tous les cas : si une balise
contient un attribut dont la valeur est une chaîne contenant un '<' (ou
'>'), l'expression ne va pas matcher la balise entière. Si on est sûr que
l'html est bien formé, on peut s'en sortir en acceptant les '<' ou '>' s'il
y a un nombre impair de " (ou de ') avant, mais ça complique l'expression.
Une bibliothèque destinée à la manipulation du html comme celle proposée par
Simon est quand même mieux adaptée.

--
Zazar
Avatar
Patrick Philippot
Zazar wrote:
Bonsoir,

La bonne expression est donc
"<[^<]*>"



Personnellement, je l'aurais plutôt écrit :
"<[^>]*>"
ca me paraît plus logique.

Sinon, cette expression ne marche pas dans tous les cas : si une
balise contient un attribut dont la valeur est une chaîne contenant
un '<' (ou '>'), l'expression ne va pas matcher la balise entière.



Bonjour,

Je suis d'accord mais votre raisonnement s'applique pareillement aux
deux cas et la question générale est effectivement: peut-on "déhtmliser"
un texte en utilisant des expressions régulières? La réponse est non, de
toute évidence. Il y aura toujours un cas de figure qui ne va pas
coller. J'ai simplement répondu à une question immédiate.

Pour avoir écrit un parseur HTML custom, je sais bien qu'HTML est
suffisamment ambigu et permissif pour ne pas pas permettre un parsing
simple. Des outils comme HTML Agility Pack ou SgmlReader peuvent aider
sans toutefois fournir de solution parfaite.

Nous serons tranquilles quand XHTML sera la norme.

--
Patrick Philippot - Microsoft MVP
MainSoft Consulting Services
www.mainsoft.fr
Avatar
laurent courbez
Patrick Philippot a écrit :
JB. Deschampheleire wrote:

Bonjour, j'aimerais supprimer toutes les balises HTML d'un texte (cad
les chaines du type <xxx>) mais il me supprime trop... c assez bizare
et pourtant l'expression reguilere que j'utilise me semble juste...
la voici:

string resultat = Regex.Replace(input,"<.*[^<]>","");

j'ai l'impression que si on a qqch du type "<TAG1> hello <TAG2>"...
il prend tout alors qu'il devrai seulement prendre <TAG1> et
<TAG2>... je ne comprend pas pq... qqn pourrait me donner la bonne
expression a utiliser pour supprimer SEULEMENT les balise (et donc,
qu'il ne reste plus que le "hello") Merci d'avance




Bonjour,

Votre expression n'est pas correcte. Par défaut, les expressions
régulières utilise le "greedy matching" ou "longest match". RegEx essaie
de trouver la chaîne la plus longue correspondant au pattern. Dans votre
expression vous spécifiez que le dernier caractère avant le > ne doit
pas être <. Donc l'ensemble de la chaîne "<TAG1> hello <TAG2>"
correspond. Vous dîtes expressément, si j'ose dire :-), que entre le <
et le > il peut y avoir n'importe quel caractère de 0 à n fois (.*) et
ensuite un caractère qui ne doit pas être <. ce qui décrit parfaitement
"<TAG1> hello <TAG2>" dans sa totalité, le dernier caractère avant le >
de <TAG2> étant 2 et pas <.

La bonne expression est donc
"<[^<]*>"

Par ailleurs, si vous avez besoin d'éviter le "greedy matching" et de
passer en mode "lazy matching" (shortest match), il vous suffit de
mettre un ? derrière le quantificateur. Voir la doc.

Pour vous familiariser avec les expressions régulières, je ne saurais
trop vous conseiller les outils Expresso (http://www.ultrapico.com/) et
The Regulator
(http://weblogs.asp.net/rosherove/archive/2004/04/20/117069.aspx).

ainsi que ce tutorial

http://www.codetools.com/useritems/RegexTutorial.asp



que pensez vous de ceci ?

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

LC.
1 2 3