Discussion:
modifier une chaine seulement hors tags html
(trop ancien pour répondre)
Xavier Brochard
2010-07-12 11:08:05 UTC
Permalink
Bonjour

Je ne sais pas si mon titre est bien choisi mais voilà:

Dans un résultat de recherche, je veux "colorer" (avec un tag html) le motif
recherché.

Dans la plupart des cas le format de résultat contiendra du code html. Mais
ce code n'est pas déterminé à l'avance, soit parce qu'il fait partie du
résultat, soit parce qu'il détermine le format et est choisi lors du
paramétrage du bazar.
Parfois le motif recherché figure aussi dans le code html, et bien
évidemment il ne faut alors pas le "colorer".

Cette expression rationnelle fonctionne assez bien, mais pas tout le temps:

eval { $print =~ s/>[^<]+/&paintFoundText($&)/gei };

(la fonction paintFoundText se contente d'ajouter un tag <span class=found>
autour du motif trouvé)

Elle a l'avantage d'être simple, et de ne pas trop ralentir le programme,
pour une "feature" de peu d'importance.

En cherchant des trucs plus élaboré (mais peu probants), je finis par penser
qu'il faudrait faire beaucoup beaucoup plus compliqué. Mais alors j'ai peur
que ça consomme trop de ressources.

Qu'en pensez vous? et avez vous des pistes?

J'ai essayé d'être clair et pas trop long, mais comme mon niveau de Perl
est faible... si c'est du charabia, engueulez-moi.

cordialement,
xavier
Nicolas George
2010-07-12 12:21:49 UTC
Permalink
Xavier Brochard wrote in message
Post by Xavier Brochard
En cherchant des trucs plus élaboré (mais peu probants), je finis par penser
qu'il faudrait faire beaucoup beaucoup plus compliqué. Mais alors j'ai peur
que ça consomme trop de ressources.
Qu'en pensez vous? et avez vous des pistes?
Il ne faut jamais manipuler directement du HTML sous forme de texte dans un
programme, c'est la porte ouverte à toutes les injections de code. Il faut
toujours manipuler le document sous forme d'arbre abstrait, et le convertir
en HTML textuel uniquement à la fin. Il y a plusieurs bibliothèques qui font
ça très bien.
Xavier Brochard
2010-07-12 12:33:02 UTC
Permalink
Post by Nicolas George
Xavier Brochard wrote in message
Post by Xavier Brochard
En cherchant des trucs plus élaboré (mais peu probants), je finis par
penser qu'il faudrait faire beaucoup beaucoup plus compliqué. Mais alors
j'ai peur que ça consomme trop de ressources.
Qu'en pensez vous? et avez vous des pistes?
Il ne faut jamais manipuler directement du HTML sous forme de texte dans
un programme, c'est la porte ouverte à toutes les injections de code. Il
faut toujours manipuler le document sous forme d'arbre abstrait, et le
convertir en HTML textuel uniquement à la fin. Il y a plusieurs
bibliothèques qui font ça très bien.
Mille pardon, je me suis mal exprimé:
le code html ne vient pas d'un formulaire (donc n'est pas entré par un
utilisateur), il vient d'un format de sortie qui a été paramétré d'avance,
mais qui varieras d'une installation à une autre.

En re-parcourant les archives de la liste, je crois qu'une liste convient
bien: d'abord on split sur les tags html (construction de la liste), puis on
modifie les éléments qui ne contiennent pas d'html (boucle for each avec un
match).

Merci pour le conseil cela dit.

xavier
Olivier Miakinen
2010-07-12 12:45:10 UTC
Permalink
Bonjour,
Post by Xavier Brochard
Post by Nicolas George
Il ne faut jamais manipuler directement du HTML sous forme de texte dans
un programme, c'est la porte ouverte à toutes les injections de code. Il
faut toujours manipuler le document sous forme d'arbre abstrait, et le
convertir en HTML textuel uniquement à la fin. Il y a plusieurs
bibliothèques qui font ça très bien.
le code html ne vient pas d'un formulaire (donc n'est pas entré par un
utilisateur), il vient d'un format de sortie qui a été paramétré d'avance,
mais qui variera d'une installation à une autre.
Je crois que tu t'étais bien exprimé, et que la réponse de Nicolas
reste valable avec ces précisions : plutôt que d'agir sur le HTML
généré, il vaudrait mieux agir sur le « format de sortie », juste
avant génération du HTML. Ce sera d'une part plus facile, et d'autre
part moins générateur de bug.

Cordialement,
--
Olivier Miakinen
Xavier Brochard
2010-07-12 13:10:20 UTC
Permalink
Post by Olivier Miakinen
Je crois que tu t'étais bien exprimé, et que la réponse de Nicolas
reste valable avec ces précisions : plutôt que d'agir sur le HTML
généré, il vaudrait mieux agir sur le « format de sortie », juste
avant génération du HTML. Ce sera d'une part plus facile, et d'autre
part moins générateur de bug.
J'aurais bien aimé que ce soit possible, mais ça ne l'est pas: le format de
sortie détermine ce qui est affiché.
Il s'agit en fait de requêtes dans une petite bases de donnés textuelle, le
"format de sortie" en liste de réponses indique le formatage html (ou pas)
et les champs affichés. Il y a un problème de conception initial qui empêche
d'agir avant le formatage de la sortie. Et je ne peux pas changer ça (pas
avant longtemps).

Merci pour la réponse, qui m'éclaire tout de même pas mal sur le défaut de
conception.

cordialement
xavier
Olivier Miakinen
2010-07-12 13:37:37 UTC
Permalink
Post by Xavier Brochard
[...] il vaudrait mieux agir sur le « format de sortie », juste
avant génération du HTML. Ce sera d'une part plus facile, et d'autre
part moins générateur de bug.
J'aurais bien aimé que ce soit possible, mais ça ne l'est pas: le format de
sortie détermine ce qui est affiché.
Il s'agit en fait de requêtes dans une petite bases de donnés textuelle, le
"format de sortie" en liste de réponses indique le formatage html (ou pas)
et les champs affichés. Il y a un problème de conception initial qui empêche
d'agir avant le formatage de la sortie. Et je ne peux pas changer ça (pas
avant longtemps).
Bon, dans ce cas je vais répondre à ta proposition précédente.
Post by Xavier Brochard
En re-parcourant les archives de la liste, je crois qu'une liste convient
bien: d'abord on split sur les tags html (construction de la liste), puis on
modifie les éléments qui ne contiennent pas d'html (boucle for each avec un
match).
Tu fais comme tu veux, mais méfie-toi quand même du fait que le texte à
remplacer pourrait se trouver, après avoir écarté les balises HTML,
dans un élément TITLE, ou un élément STYLE, où il ne faudrait pas faire
le remplacement, voire dans un élément SCRIPT, où remplacer pourrait
être parfois désirable et parfois dangereux.

Cordialement,
--
Olivier Miakinen
Olivier Miakinen
2010-07-12 13:46:09 UTC
Permalink
Post by Olivier Miakinen
Post by Xavier Brochard
En re-parcourant les archives de la liste, je crois qu'une liste convient
bien: d'abord on split sur les tags html (construction de la liste), puis on
modifie les éléments qui ne contiennent pas d'html (boucle for each avec un
match).
Tu fais comme tu veux, mais méfie-toi quand même du fait que le texte à
remplacer pourrait se trouver, après avoir écarté les balises HTML,
dans un élément TITLE, ou un élément STYLE, où il ne faudrait pas faire
le remplacement, voire dans un élément SCRIPT, où remplacer pourrait
être parfois désirable et parfois dangereux.
Ah, il y a aussi les éléments OPTION et TEXTAREA qui posent problème. Je
ne sais pas si j'en oublie (mais c'est probablement le cas).
Xavier Brochard
2010-07-12 14:15:47 UTC
Permalink
Post by Olivier Miakinen
méfie-toi quand même du fait que le texte à
remplacer pourrait se trouver, après avoir écarté les balises HTML,
dans un élément TITLE, ou un élément STYLE, où il ne faudrait pas faire
le remplacement, voire dans un élément SCRIPT, où remplacer pourrait
être parfois désirable et parfois dangereux.
oui en effet, j'ai posté trop vite...
il y a aussi IFRAME dont je devrai me méfier.

merci d'attirer mon attention là-dessus.

cordialement
xavier
Olivier Miakinen
2010-07-12 15:52:14 UTC
Permalink
Post by Xavier Brochard
Post by Olivier Miakinen
méfie-toi quand même du fait que le texte à
remplacer pourrait se trouver, après avoir écarté les balises HTML,
dans un élément TITLE, ou un élément STYLE, où il ne faudrait pas faire
le remplacement, voire dans un élément SCRIPT, où remplacer pourrait
être parfois désirable et parfois dangereux.
oui en effet, j'ai posté trop vite...
il y a aussi IFRAME dont je devrai me méfier.
Euh... IFRAME, je ne vois pas pourquoi il aurait besoin d'un traitement
particulier. Mais TITLE, STYLE, SCRIPT, OPTION et TEXTAREA, oui. Qui
plus est, le caractère '>' peut légitimement se trouver n'importe où en
dehors des balises, et le caractère '<' peut aussi se trouver dans un
élément SCRIPT, ce qui fait que ton split par expression rationnelle ne
suffit pas à gérer ces cas.

Seule solution viable : utiliser un parseur de HTML pour obtenir un
arbre abstrait représentant le document, faire tes petites manips sur
les feuilles de cet arbre (sauf bien sûr TITLE, STYLE, SCRIPT, OPTION et
TEXTAREA), et enfin regénérer un code HTML textuel à la fin. On en
revient à ce que conseillait Nicolas au début de ce fil.

Cordialement,
--
Olivier Miakinen
Xavier Brochard
2010-07-12 22:41:28 UTC
Permalink
Post by Olivier Miakinen
Seule solution viable : utiliser un parseur de HTML pour obtenir un
arbre abstrait représentant le document, faire tes petites manips sur
les feuilles de cet arbre (sauf bien sûr TITLE, STYLE, SCRIPT, OPTION et
TEXTAREA), et enfin regénérer un code HTML textuel à la fin. On en
revient à ce que conseillait Nicolas au début de ce fil.
CQFD! merci pour tous ces (bons) conseils

et puisque on en revient au début, est ce que ça ne va pas être un peu lourd
pour une "feature" de peu d'importance?


xavier
Olivier Miakinen
2010-07-13 11:27:20 UTC
Permalink
[utiliser un parseur de HTML]
[...] puisque on en revient au début, est ce que ça ne va pas être un peu lourd
pour une "feature" de peu d'importance?
Tout dépend de ce que recouvre ce « peu » d'importance.

S'il n'est pas grave que ça casse parfois des scripts JavaScript ou que
ça rende le document invalide en allant charcuter un élément TITLE ou
OPTION, parce que tu es toujours là pour réparer les choses à la main en
cas de besoin, alors oui, tu peux faire au plus simple. À la limite tu
n'as même pas besoin de programme : il te suffit de faire un petit coup
de vim dans les fichiers HTML qui t'intéressent.

Mais si tu préfères que ça fonctionne sans que tu aies besoin
d'inspecter un à un chaque résultat, alors ce sera moins lourd
d'utiliser un vrai parseur que de tenter de prévoir tous les cas via des
regexp. D'ailleurs Paul a confirmé que les parseurs HTML fonctionnaient
vite et bien (cela dit je ne peux pas t'en conseiller moi-même car je ne
connais pas encore Perl).

Cordialement,
--
Olivier Miakinen
Xavier Brochard
2010-07-12 13:54:52 UTC
Permalink
Post by Xavier Brochard
En re-parcourant les archives de la liste, je crois qu'une liste convient
ce n'est pas très élégant, mais ça marche bien:

my @listHtml = split (/(<[^>\s]+>)/,$print);
$print = "";
foreach $x (@listHtml) {
$x = &paintFoundText($x) if ($x !~ m/^</);
$print .= $x;
}
(la fonction paintFoundText se contente d'ajouter un tag <span class=found>
autour du motif trouvé)


xavier
Paul Gaborit
2010-07-13 07:45:19 UTC
Permalink
À (at) Mon, 12 Jul 2010 15:54:52 +0200,
Post by Xavier Brochard
Post by Xavier Brochard
En re-parcourant les archives de la liste, je crois qu'une liste convient
$print = "";
$x = &paintFoundText($x) if ($x !~ m/^</);
$print .= $x;
}
(la fonction paintFoundText se contente d'ajouter un tag <span class=found>
autour du motif trouvé)
Je n'ajoute rien aux autres réponses données sur le fond du problème (je
suis d'accord avec les suggestions données et les parseurs HTML
fonctionnent vite et bien pour un résultat plus simple à mettre en
oeuvre au final).

Juste une remarque : n'utilisez pas le '&' pour appeler votre fonction
paintFoundText.

Petit extrait de 'perlsub' :

To call subroutines:

NAME(LIST); # & is optional with parentheses.
NAME LIST; # Parentheses optional if predeclared/imported.
&NAME(LIST); # Circumvent prototypes.
&NAME; # Makes current @_ visible to called subroutine.

Les deux derniers exemples de syntaxe ne sont que très rarement utilisés
et peuvent avoir des effets non voulus si on les utilise à tort... Le
simple usage des parenthèses permet de lever les ambiguïtés.
--
Paul Gaborit - <http://perso.mines-albi.fr/~gaborit/>
Perl en français - <http://perl.mines-albi.fr/>
Xavier Brochard
2010-07-26 10:28:04 UTC
Permalink
Post by Paul Gaborit
Post by Xavier Brochard
$x = &paintFoundText($x) if ($x !~ m/^</);
...
...
Juste une remarque : n'utilisez pas le '&' pour appeler votre fonction
paintFoundText.
ah oui c'est un oubli!
ce script a longtemps tourné avec Perl4, il est encore plein de vieilleries,
et du coup à force d'en lire... on en écrit!

merci pour toute l'aide apportée à mes questions de novice.

xavier

Loading...