OVH Cloud OVH Cloud

Recherches / remplacements dans une chaine, quelle est la meilleure methode ?

8 réponses
Avatar
Eric Demeester
Bonjour,

Désolé si la question a déjà été posée, si quelqu'un me répond RTFM en
me donnant un lien, je ne lui en voudrai pas :)

Ce que je souhaite faire n'est pas très compliqué. J'ai une base de
données comprenant un lexique professionnel contenant deux champs
principaux : le nom de l'entrée et sa définition. Le visiteur interroge
la base et obtient un certain nombre de couples nom/définition en
fonction des critères de recherche indiqués, qui s'affichent à l'écran.
Jusque là tout va bien :)

La définition de certains termes fait appel à d'autres termes « métier »
présents dans la base, j'aimerais rendre ces termes « cliquables » afin
que le visiteur puisse de reporter facilement à leur définition.

Je souhaite aussi, parce que la personne qui va enrichir le lexique
n'est pas une pro, ne pas l'obliger à entrer une URL en dur lorsqu'un
tel terme est indiqué, mais simplement un caractère spécial (#, disons)
devant le terme en question, faisant office de balise m'indiquant que je
dois traiter le mot.

J'ai imaginé la solution suivante. Lorsque je récupère une définition à
afficher suite à la requète du visiteur :

- je stocke la définition mot à mot dans un tableau :

$mots = explode(" ", $definition);

- je dénombre le nombre d'éléments (mots) de mon tableau :

$nombre_mots = count($mots);

- je traite les mots un à un et si je tombe sur un terme figurant dans
le lexique (débutant par #, donc) , je le transforme en URL :

for ($i=0, $i=$nombre_mots, $i++) {
if (substr($mots[$i], 0, 1) == '#') {
// je vire le caractère spécial
$mots[$i] = ltrim($mots[$i],'#') ;
// je construis mon url :
$mots[$i] = '<a href="page_de_destination.php?' . $mots[$i] . '">' .
$mots[$i] . '</a>';
}
}

- enfin, je reconstitue le texte à afficher :

$definition = implode(" ",$mots);

Ca vous semble cohérent, compliqué, il y a des erreurs dans mon code,
j'ai réinventé la roue ?

J'ai tendance à être un peu « agricole » dans ma façon de programmer
(comprendre plutôt lourd, pas bien malin et dérouté quand ça devient
trop subtil...), donc si vous avez mieux à me proposer, n'hésitez pas :)

--
Eric

8 réponses

Avatar
CrazyCat
$mots = explode(" ", $definition);
$nombre_mots = count($mots);
for ($i=0, $i=$nombre_mots, $i++) {
if (substr($mots[$i], 0, 1) == '#') {
// je vire le caractère spécial
$mots[$i] = ltrim($mots[$i],'#') ;
// je construis mon url :
$mots[$i] = '<a href="page_de_destination.php?' . $mots[$i] . '">' .
$mots[$i] . '</a>';
}
}
$definition = implode(" ",$mots);


il serait peut-être plus simple d'utiliser une expression régulière pour
faire un remplacement:
$definition = preg_replace("/#([^ ]+)/Us", '<a
href="page_destination.php?mot=1">1</a>', $definition);

(je ne garanti pas l'exactitude de la regexp)

--
Astuces pour webmasters: http://www.crazycat.info
Tchat francophone: http://www.crazy-irc.net

Avatar
Olivier Miakinen

[...]

- je traite les mots un à un et si je tombe sur un terme figurant dans
le lexique (débutant par #, donc) , je le transforme en URL :

for ($i=0, $i=$nombre_mots, $i++) {


Ce serait plutôt $i < $nombre_mots
(sinon, tu fais une boucle infinie qui teste une infinité de fois un
élément d'index supérieur à tous ceux qui existent) :-D

if (substr($mots[$i], 0, 1) == '#') {
// je vire le caractère spécial
$mots[$i] = ltrim($mots[$i],'#') ;


À moins que tu le rédacteur ait une touche # qui rebondit, il suffit de
virer le premier caractère (mais ta méthode marche aussi bien) :
$mots[$i] = substr($mots[$i], 1) ;

[...]

Ca vous semble cohérent, compliqué, il y a des erreurs dans mon code,
j'ai réinventé la roue ?


Ça me semble cohérent, j'ai corrigé au moins une erreur (je n'en ai
pas vu d'autre en lecture rapide), mais je proposerais bien un simple
preg_replace() au lieu de toutes ces lignes de code.

$pattern = '/#([^ ]+)/'; /* Un # suivi de n caractères sans espace */
$replacement = '<a href="page_de_destination.php?$1">$1</a>';
$definition = preg_replace($pattern, $replacement, $definition);

« Les PCRE c'est bon : mangez-en ! »

Avatar
P'tit Marcel
Hello,


La définition de certains termes fait appel à d'autres termes « métier »
présents dans la base, j'aimerais rendre ces termes « cliquables » afin
que le visiteur puisse de reporter facilement à leur définition.

Je souhaite aussi, parce que la personne qui va enrichir le lexique
n'est pas une pro, ne pas l'obliger à entrer une URL en dur lorsqu'un
tel terme est indiqué, mais simplement un caractère spécial (#, disons)
devant le terme en question, faisant office de balise m'indiquant que je
dois traiter le mot.


Pour rendre cliquable certains mots d'un texte, je crois que la solution
classique est plutôt par les expressions régulières, genre :


$texte = "truc machin chouette #mot bidule #autremot: tsointsoin";

$masque = '`#(w+)`';
$remplace = '<a href="page_de_destination.php?$1">$1</a>';

$texte_avec_lien = preg_replace($masque, $remplace, $texte);


eça
--
P'tit Marcel
stats sur les forums modérés http://www.centrale-lyon.org/ng/

Avatar
Eric Demeester
dans (in) fr.comp.lang.php, Olivier Miakinen <om+
ecrivait (wrote) :

Bonjour Olivier,

for ($i=0, $i=$nombre_mots, $i++) {


Ce serait plutôt $i < $nombre_mots
(sinon, tu fais une boucle infinie qui teste une infinité de fois un
élément d'index supérieur à tous ceux qui existent) :-D


Damned, tu as raison !

if (substr($mots[$i], 0, 1) == '#') {
// je vire le caractère spécial
$mots[$i] = ltrim($mots[$i],'#') ;


À moins que tu le rédacteur ait une touche # qui rebondit, il suffit de
virer le premier caractère (mais ta méthode marche aussi bien) :
$mots[$i] = substr($mots[$i], 1) ;


Oui. Je débute en php, donc je n'ai pas encore une connaissance
suffisante des différentes instructions. Même si dans ma tête je sais
comment je procéderais avec d'autres langages, je me rends compte que
là, je n'ai pas encore les bons réflexes...

Ça me semble cohérent, j'ai corrigé au moins une erreur (je n'en ai
pas vu d'autre en lecture rapide), mais je proposerais bien un simple
preg_replace() au lieu de toutes ces lignes de code.


Même réponse de CrazyCat :)

« Les PCRE c'est bon : mangez-en ! »


Je vais étudier attentivement vos suggestions, mais comme dit
précédemment, je suis un programmeur du dimanche, même si ça fait 25 ans
que je joue à ça, et les expressions rationnelles, je n'y comprends pas
grand-chose :(

--
Eric


Avatar
Olivier Miakinen

il serait peut-être plus simple d'utiliser une expression régulière pour
faire un remplacement:
$definition = preg_replace("/#([^ ]+)/Us", '<a
href="page_destination.php?mot=1">1</a>', $definition);


Nos propositions sont très similaires !

Je me permettrai juste quelques remarques, à la lumière de la lecture de
la doc.

1) [^ ]

L'espace n'étant pas un caractère spécial dans les chaînes, que ce soit
dans des simples ou doubles guillemets, le caractère "" est conservé.
Comme l'espace n'est pas non plus un caractère spécial entre crochets
dans une expression rationnelle, il est inutile de l'échapper par .
Mais si j'en crois la doc ça ne fait pas de mal non plus (j'avais peur
que [^ ] soit équivalent à [^ ] mais il semble équivalent à [^ ]).

Bref : pour ne pas se poser de questions métaphysiques, je préfère ne
pas échapper ce qui n'a pas besoin de l'être. Je préfère donc écrire
[^ ] tout simplement.

2) /Us

L'option s ne sert que quand tu utilises le caractère spécial « . » pour
préciser si oui ou non il peut être mis en correspondance avec un saut
de ligne. Elle est parfaitement inutile ici puisque tu n'utilises pas
de « . ».

Quant à l'option U, elle peut être utile en effet pour ne pas prendre
« #mot-#composé » pour un seul mot.

À ce propos, Éric, il serait bon de préciser quelles sont les vraies
limites de mots. Par exemple, il me semble qu'un point ou une virgule
devrait être exclu du mot, mais pour le trait d'union cela peut dépendre
des mots (#mot-composé -> mot ou mot-composé ?)

3) 1

D'après la doc, c'est soit 1 soit $1 avec une préférence pour $1 (cela
dit, 1 est équivalent à 1).


Finalement, Éric, pour éviter toute ambiguïté, tu pourrais peut-être
demander comme syntaxe #mot# au lieu de simplement #mot, ce qui
permettrait au rédacteur de fixer précisément où chaque mot s'arrête.
Dans cette hypothèse, le $pattern serait '/#([^#]+)#/'. Et si tu veux
aider à la détection des erreurs, cela peut même être
'/#([^#s.,;:!?]+)#/' ou un truc de ce genre.

Avatar
CrazyCat
Nos propositions sont très similaires !


les grands esprits...

Je me permettrai juste quelques remarques, à la lumière de la lecture de
la doc.
1) [^ ]
Bref : pour ne pas se poser de questions métaphysiques, je préfère ne
pas échapper ce qui n'a pas besoin de l'être. Je préfère donc écrire
[^ ] tout simplement.


Lorsque j'ai un doute sur un caractère "spécial", je l'échappe. Et je
considère en gros que tout caractère echappé en console linux doit
l'être (j'aurais d'ailleurs dû, dans cette logique, échapper le #)

2) /Us
L'option s ne sert que quand tu utilises le caractère spécial « . » pour
préciser si oui ou non il peut être mis en correspondance avec un saut
de ligne. Elle est parfaitement inutile ici puisque tu n'utilises pas
de « . ».


Effectivement, c'est une erreur due à une mauvaise adaptation :)

Quant à l'option U, elle peut être utile en effet pour ne pas prendre
« #mot-#composé » pour un seul mot.


on a bien dit un caractère unique? donc je pars du principe que
#mot-#composé va vers deux définitions :)

3) 1
D'après la doc, c'est soit 1 soit $1 avec une préférence pour $1 (cela
dit, 1 est équivalent à 1).


Oui, j'ai fait une erreur, c'est bien 1 qu'il fallait lire. Et oui
encore, $1 est préférable, ne serait-ce que pour une question de lisibilité.

--
Astuces pour webmasters: http://www.crazycat.info
Tchat francophone: http://www.crazy-irc.net

Avatar
Olivier Miakinen

Je me permettrai juste quelques remarques, à la lumière de la lecture de
la doc.
1) [^ ]
Bref : pour ne pas se poser de questions métaphysiques, je préfère ne
pas échapper ce qui n'a pas besoin de l'être. Je préfère donc écrire
[^ ] tout simplement.


Lorsque j'ai un doute sur un caractère "spécial", je l'échappe. Et je
considère en gros que tout caractère echappé en console linux doit
l'être (j'aurais d'ailleurs dû, dans cette logique, échapper le #)


C'est compréhensible quand tu n'as pas accès à la doc pour vérifier,
mais tout aussi risqué que de ne pas l'échapper. Par exemple, si tu fais
« echo "J'échappe l'apostrophe"; » en espérant jouer la sécurité, tu
vas te retrouver avec deux en trop à l'affichage.

Quant à l'option U, elle peut être utile en effet pour ne pas prendre
« #mot-#composé » pour un seul mot.


on a bien dit un caractère unique? donc je pars du principe que
#mot-#composé va vers deux définitions :)


Oui, mais du coup ça ne marchera pas non plus parce que le premier
lien ira vers « mot- » au lieu de « mot ». Et inversement si on veut
interdire le trait d'union cela empêche d'utiliser #mot-composé pour
mettre un lien vers « mot-composé ».

L'idée des deux # permettrait de choisir :
« On peut rencontrer des #mots#-composés avec ou sans #traits d'union#
comme, par exemple, une #pomme de terre#. »


Avatar
Florian Sinatra
*Eric Demeester* @ 19/09/2006 15:55 :
Je vais étudier attentivement vos suggestions, mais comme dit
précédemment, je suis un programmeur du dimanche, même si ça fait 25 ans
que je joue à ça, et les expressions rationnelles, je n'y comprends pas
grand-chose :(


Quelques pistes pour commencer ;-) :
* http://www.expreg.com/ (en maintenance actuellement)
* http://ch2.php.net/manual/fr/reference.pcre.pattern.syntax.php (plus
accessible mais moins rigoureux)
*
http://www.siteduzero.com/tuto-3-168-1-les-expressions-regulieres-partie-1-2.html
* http://g-rossolini.developpez.com/tutoriels/php/expressions-regulieres/
* http://cyberzoide.developpez.com/php4/regex/