Précédent   Forum du club des développeurs et IT Pro > PHP > Langage > Regex
Regex Forum d'entraide sur les expressions rationnelles PHP. Avant de poster -> FAQ regex, Cours de regex et Sources de regex
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 06/11/2012, 13h47   #1
bobic
Membre régulier
 
Inscription : mai 2005
Messages : 359
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 359
Points : 81
Points : 81
Par défaut Regex pour placer un lien sur un mot clé, lui même sans lien

Hello,

J'ai un petit soucis depuis quelques temps....

En effet, je désire faire un regex pour placer un lien sur un mot clé (que je récupère via une requête sql). Jusque là pas de soucis.

Mon problème, c'est que certains de mes mots clés font déjà partie d'un lien... ce qui me fait donc un code html invalide.

Mon but est donc de rechercher mon mot clé par rapport à une liste (ça ok), puis de vérifier que ce mot clé ne comporte pas de balise <a devant lui (immédiatement ou pas) sans balise fermante, ni qu'il n'y a pas de balise </a> après sans balise ouvrante. En dautres mots donc, je ne veux pas que mon mot clé soit en plein milieu d'un lien. Ex:

Code :
1
2
<a .....> Une phrase avec mon mot clé</a>  <--- NON
<a....> Une phrase</a>avec mon mot clé <a...>ici</a> OUI
Pour le moment, mon code ressemble à cela:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 
class autolink {
 
    public function parse($description) {
 
        //Recuperation de la liste des mots cés
        require_once(config::getPathClasses() . 'service/ServiceLiensDynamique.php');
        $liensDyn = new ServiceLiensDynamique(config::$tableLiensDynamiques);
        $resultLiensDyn = $liensDyn->getLiensDynamiques(config::$siteInt);
 
         //Boucle sur chaque mot clé
        foreach($resultLiensDyn as $resultLiensDyn){
            $lien = config::getAccueil().$resultLiensDyn['lien']; //lien a appliquer
            $nom = $resultLiensDyn['nom'];
 
            $arrayARemplacer[] = $resultLiensDyn['nom'];
            $arrayRemplacement[] = "<strong><a href=\"$lien\" title=\"$nom\">$nom</a></strong>";
        }
 
        $description = str_ireplace($arrayARemplacer, $arrayRemplacement, $description,$count);
 
        //TODO vérifier qu'il n'y a pas de liens déjà présent via une balise </a> 
 
       }
 
}

Merci pour votre aide !!
bobic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 08/11/2012, 18h25   #2
bobic
Membre régulier
 
Inscription : mai 2005
Messages : 359
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 359
Points : 81
Points : 81
Personne ne peut m'aider ?

Pour rappel (et simplification de l'énoncé de mon problème) mon but est de pouvoir créer des liens sur des mots clés qui ne disposeraient pas déjà d'un lien.

Je me suis cassé la tête toute la journée sur ça, sans réussite... En gros donc, je veux pouvoir dans mon regex récupérer les mots clés désirés qui ne disposeraient pas d'un <a href devant le mot et d'un </a> derrière.

Merci
bobic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/11/2012, 15h31   #3
mokfajri
Membre à l'essai
 
Homme
Développeur Web
Inscription : avril 2009
Messages : 19
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations professionnelles :
Activité : Développeur Web

Informations forums :
Inscription : avril 2009
Messages : 19
Points : 24
Points : 24
Bonjour,

Voilà une solution à ton problème (si j'ai bien compris):
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
 
$string = '<a href="non"> Une phrase avec mon mot cle</a>
<a href="oui"> Une phrase</a>avec mon mot cle <a...>ici</a>';
 
$mot_cle = 'mot cle';
$lien = "lien";
$pattern = "/([^(?:<a .*?>)]*?)($mot_cle)([^(?:<\/a>)]+)/i";
$replacement = "<strong><a href=\"$lien\" title=\"$mot_cle\">$mot_cle</a></strong>";
 
echo $string."\n";
 
echo "--------------------------------------------\n";
echo preg_replace($pattern, $replacement, $string);
mokfajri est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/11/2012, 16h18   #4
bobic
Membre régulier
 
Inscription : mai 2005
Messages : 359
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 359
Points : 81
Points : 81
Oui, tu as parfaitement compris, et cela semble bien marcher

Je n'ai jamais été très fort en REGEX, et j'en ai chié sur les exclusions... Lors de mes tests, cela me supprimait carrément des bouts de la chaine...

En un seul coup, tu as réussi, un grand merci à toi !
bobic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 09/11/2012, 17h36   #5
bobic
Membre régulier
 
Inscription : mai 2005
Messages : 359
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 359
Points : 81
Points : 81
Il subiste quelques petits soucis que je n'avais pas pris en comte (si le mot clé est présent dans une balise <img,...
Je vais donc travailler dessus et posterai le tout si des fois ça peut servir à d'autres
bobic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/11/2012, 19h12   #6
bobic
Membre régulier
 
Inscription : mai 2005
Messages : 359
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 359
Points : 81
Points : 81
Je suis de retour

Le code marche super sur de simples liens, mais si le mot clé se retrouve dans un alt, dans un <img src, dans un title, ou même dans un url ça ne fonctionne plus.

J'ai donc essayé de rajouter le img, le alt=" et le title=" sans succès... soit ça me répète un nombre incalculable de fois le mot clé, soit cela me coupe la phrase...

Mon code actuel est donc le suivant:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
$string = '<a href="non" title="motcle en action"> Une phrase avec motcle</a>.
<a href="oui" title="oui"> Une phrase</a>     avec motcle   <a href="aucun"> ici</a>.';
 
$mot_cle = 'motcle ';
$lien = "http://google.fr";
/*$pattern = "/([^(?:<a .*?>)]*?)($mot_cle)([^>]+)/i"; */
 
//$pattern = "/([^(title=>)]*?)[\s]+($mot_cle)[\s]+/i";
$pattern = "/[\s]*([^(?:<a .*?>)]*?)($mot_cle)([^(?:<\/a>)]+)/i";
 
 
$replacement = " <strong><a href=\"$lien\" title=\"$mot_cle\">$mot_cle</a></strong> ";
 
echo "Original: $string.\n";
 
echo "<br/>Modifié: \n";
echo preg_replace($pattern, $replacement, $string);
En l'éxécutant, je me retrouve avec ça:

Citation:
Original: <a href="non" title="motcle en action"> Une phrase avec motcle</a>.
<a href="oui" title="oui"> Une phrase</a> avec motcle <a href="aucun"> ici</a>..
<br/>Modifié:
<a href="non" <strong><a href="http://google.fr" title="motcle ">motcle </a></strong> action"> Une phrase avec motcle</a>.
<a href="oui" title="oui"> Une phrase</a> avec <strong><a href="http://google.fr" title="motcle ">motcle </a></strong> <a href="aucun"> ici</a>.
J'ai également essayé de rajouter le fait que je veux qu'il y ait un espace de chaque côté de mon clé mais le résultat est très bizarre...
En effet soit je ne met qu'un seul espace dans ma chaine, et ça ne prend pas, soit j'en place plusieurs, et dans ce cas, mon texte est tronqué

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
$string = '<a href="non" title="motcle en action"> Une phrase avec motcle</a>.
<a href="oui" title="oui"> Une phrase</a>avec motcle        <a href="aucun"> ici</a>.';
 
$mot_cle = 'motcle ';
$lien = "http://google.fr";
/*$pattern = "/([^(?:<a .*?>)]*?)($mot_cle)([^>]+)/i"; */
 
//$pattern = "/([^(title=>)]*?)[\s]+($mot_cle)[\s]+/i";
$pattern = "/[\s]*([^(?:<a .*?>)]*?)[\s]+($mot_cle)[\s]+([^(?:<\/a>)]+)/i";
 
 
$replacement = " <strong><a href=\"$lien\" title=\"$mot_cle\">$mot_cle</a></strong> ";
 
echo "Original: $string.\n";
 
echo "<br/>Modifié: \n";
echo preg_replace($pattern, $replacement, $string);
Citation:
Original: <a href="non" title="motcle en action"> Une phrase avec motcle</a>.
<a href="oui" title="oui"> Une phrase</a>avec motcle <a href="aucun"> ici</a>..
<br/>Modifié:
<a href="non" title="motcle en action"> Une phrase avec motcle</a>.
<a href="oui" title="oui"> Une phrase</a>a <strong><a href="http://google.fr" title="motcle ">motcle </a></strong> <a href="aucun"> ici</a>.
Comment se fait-il que mon texte soit tronqué ??

Bref, j'ai de grosses lacunes
bobic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 10/11/2012, 21h10   #7
bobic
Membre régulier
 
Inscription : mai 2005
Messages : 359
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 359
Points : 81
Points : 81
Apparement, j'ai trouvé quelque chose qui a l'air de bien fonctionner

Code :
1
2
 
preg_replace("|(?!<[^<>]*?)(?<![?./&])\b(motcle)\b(?!:)(?![^<>]*?>)|imsU","<a href=\"\">$1</a>" , $string);
bobic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/11/2012, 19h19   #8
CosmoKnacki
Membre habitué
 
Avatar de CosmoKnacki
 
Homme
Inscription : mars 2009
Messages : 106
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : mars 2009
Messages : 106
Points : 129
Points : 129
Bonjour,

Malheureusement cette dernière pattern laisse passer le texte des liens et provoque par conséquent des liens imbriqués, ce qui est mal.

À défaut de le faire en une seule ligne tu peux séparer ta chaine de départ avec preg_split avec l'option PREG_SPLIT_DELIM_CAPTURE en utilisant comme séparateur les cas de figure à éviter
(ie:
  • le mot clé est déjà encadré par des balises de lien
  • le mot clé se retrouve dans un attribut de balise)
ce qui te donne un tableau dans lequel va s'alterner les éléments sans séparateur et le séparateur lui même (capturer grace à l'option).
Reste plus qu'à effectuer le remplacement du mot clé, le cas échéant, dans les items qui ne sont pas le séparateur (soit un sur deux) et à recoller le tableau.

Soit:
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
$pattern="/(  # parenthèses pour capturer le séparateur
                 <a\s.*<\/a> # on match les liens
                 | # ou
                 <[^>]*\"[^\"]*${motcle}[^\"]*\"[^>]*> # le mot clé dans un attribut
                 )/sxU"; // regex non gloutonne, avec recherche multiligne
 
// (/x permet d'écrire une regex avec des espaces et des sauts de lignes pour commenter)
 
$string=" $string"; // on insère un caractère bidon (ici un espace) pour être sûr que les items du tableau à traiter seront sur les indexs pairs.
 
$tab=preg_split($pattern,$string,-1,PREG_SPLIT_DELIM_CAPTURE);
 
// on traite
 
for ($i = 0; $i < count($tab); $i+=2) {
    $tab[$i]=preg_replace("/(\b$motcle\b)/i","<a href=\"\">$1</a>",$tab[$i]);
}
 
// on recolle et on enlève le caractère bidon
 
$string=substr(implode("",$tab),1);
Maintenant, il est clair que ce problème peut se traiter avec une seule regex, mais bon là ça marche. J'espère pour toi qu'il n'y a pas de javascript dans la page contenant le mot clé!
CosmoKnacki est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/11/2012, 20h02   #9
bobic
Membre régulier
 
Inscription : mai 2005
Messages : 359
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 359
Points : 81
Points : 81
Oui, tu as raison, cela me fait des liens imbriqués ! C'est moche, et pas forcément super bien par rapport à ce que je veux faire, mais c'est valide W3C (xhtml trans).

Je te remercie par avance pour ton code. Je vais essayer cela rapidement. Mais en tout cas, ce serait parfait si ça marche, que sa se fasse en une seule ou deux étapes
bobic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/11/2012, 02h00   #10
CosmoKnacki
Membre habitué
 
Avatar de CosmoKnacki
 
Homme
Inscription : mars 2009
Messages : 106
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : mars 2009
Messages : 106
Points : 129
Points : 129
Citation:
C'est moche, et pas forcément super bien
Quel sens du compliment!
Citation:
mais c'est valide W3C
En même temps, c'est du PHP.

Teste bien.
CosmoKnacki est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/11/2012, 12h39   #11
bobic
Membre régulier
 
Inscription : mai 2005
Messages : 359
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 359
Points : 81
Points : 81
Quand je disais moche, pas super bien, et valide w3C, c'était mon code qui faisait des doubles liens, pas ton code
bobic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/11/2012, 18h07   #12
CosmoKnacki
Membre habitué
 
Avatar de CosmoKnacki
 
Homme
Inscription : mars 2009
Messages : 106
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : mars 2009
Messages : 106
Points : 129
Points : 129
Code :
1
2
3
4
5
6
7
8
9
10
11
$pattern="/(  # parenthèses pour capturer le séparateur
            <a\s.*<\/a> # on match les liens
            | # ou
            <script.*<\/script> # quelques autres trappes à éviter
            |
            <style.*<\/style>
            |
            <title.*<\/title>
            |                 
            <[^>]*\"[^\"]*${motcle}[^\"]*\"[^>]*> # le mot clé dans un attribut
           )/sxU"; // regex non gloutonne, avec recherche multiligne
reste aprés les cas particuliers, exemple:

le mot clef recherché est le mot: class
CosmoKnacki est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/11/2012, 18h32   #13
bobic
Membre régulier
 
Inscription : mai 2005
Messages : 359
Détails du profil
Informations forums :
Inscription : mai 2005
Messages : 359
Points : 81
Points : 81
J'ai essayé tout à l'heure ton code, cela a l'air de bien fonctionner sur me données de test, ce qui est déjà un bon point

Sauf cas super exceptionnel, mes mots clés ne seront pas des mots "réservés" utilisés en html. On n'est pas à l'abris, c'est sur, mais en théorie, point de problèmes.
Ceci dit, en faisant un regex qui interdit que le mot clé soit entre < ... et > on devrait pouvoir s'en sortir non ?
bobic est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/11/2012, 20h21   #14
CosmoKnacki
Membre habitué
 
Avatar de CosmoKnacki
 
Homme
Inscription : mars 2009
Messages : 106
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : mars 2009
Messages : 106
Points : 129
Points : 129
si a<b<c alors c>a (le mot clé est "alors")
CosmoKnacki est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/02/2013, 16h06   #15
CosmoKnacki
Membre habitué
 
Avatar de CosmoKnacki
 
Homme
Inscription : mars 2009
Messages : 106
Détails du profil
Informations personnelles :
Sexe : Homme
Localisation : France

Informations forums :
Inscription : mars 2009
Messages : 106
Points : 129
Points : 129
Pour revenir sur cet ancien sujet, il y avait beaucoup plus simple, en une seule étape:

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$motclef="motcle";
$string = <<<LOD
<a href="non" title="motcle en action"> Une phrase avec $motclef</a>.
<img src="/path/$motclef.jpg" />
<!-- $motclef -->
<span class="abc$motclef">def $motclef ghi</span>
<span> un{$motclef}contenu dans un autre mot</span>
<a href="oui" title="oui"> Une phrase</a>avec $motclef        <a href="aucun"> ici</a>.
LOD;
// TSE SULOBAID LMTH NI XEGER
$pattern = "~(?:<(a|script|style|title)\s.*</(?1)>) # matche les liens, script, styles
            |(?:<!--.*-->)                          # matche les commentaires
            |(?:<[^>]+>)                            # matche les balises (et leur intérieur) restantes
            |(\b$motclef\b)                         # matche le mot clef sauf s'il est contenu dans un autre mot
            |(?:.)                                  # matche le reste caractère par caractère
            ~sUx";
function cbReplace($matches) {
    return (isset($matches[2]))?"<a href=\"\">{$matches[2]}</a>":$matches[0];
}
$result = preg_replace_callback($pattern, "cbReplace", $string);
print_r($result);
CosmoKnacki est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 08h52.


 
 
 
 
Partenaires

Hébergement Web