Extraire des mots clés d'un texte

Résolu
pifethercule Messages postés 19 Date d'inscription lundi 8 février 2010 Statut Membre Dernière intervention 29 mars 2010 - 20 mars 2010 à 21:33
pifethercule Messages postés 19 Date d'inscription lundi 8 février 2010 Statut Membre Dernière intervention 29 mars 2010 - 24 mars 2010 à 03:00
Bonjour,

j'essaye d'extraire des mots clés de textes... mes mots clés sont dans une variable "$keywords" tous séparés par un pipe "|", pour faire des OU dans ma regex

les mots clés que je "match", vont normalement dans une array "$resultat", je veux récupérer tous mes mots présent dans le texte 0 ou 1 fois

donc pour le moment ce qui s'approche le plus de ce que je veux faire donne ça
function motsCles($keywords, $txt){
$pattern = "#([".$keywords."]+)#i";

if(preg_match($pattern, $txt, $resultat)){
$rMotsCles ="";
for ($i=1; $i<count($resultat) && $i<10; $i++){
    $rMotsCles .= "<mot_cle_".$i.">".$resultat[$i]."</mot_cle_".$i.">";
}
return $rMotsCles ;
}
}


donc la ça reconnait bien mes mot clé, mais je ne récupère que le premier présent

l'erreur vient de ma regex ou de la syntaxe du preg_match ? ou d'ailleurs ?

merci d'avance

14 réponses

pifethercule Messages postés 19 Date d'inscription lundi 8 février 2010 Statut Membre Dernière intervention 29 mars 2010
23 mars 2010 à 14:28
bon voila ça marche

désolé kohntark, mais vu que je m'étais embarqué dans ma façon je n'ai pas trop approfondi la tienne...

donc pour ceux que ça intéresse, ça me sert pour une partie un export d'une base mysql vers un fichier xml

ma variable "$keywords" est sous la forme (mot1)|(mot2)|...|(motn); je fais les tests sur un peu plus de 100 mots

ma variable "$txt" à été passée en minuscule juste avant pour éviter les doublons

la sortie est une concaténation de tous les mots trouvés, sous la forme "<mot_cle_n><![CDATA[mot clé]]></mot_cle_n>", limitée à 10 mots maximum

/*
fonction pour extraire les mots clé du texte, sortie = balise <mot_cle_n> mot cle trouvé <mot_cle_n>
*/
function motsCles($keywords, $txt){

$pattern = "#(".$keywords.")+?#imU";//motif: recherche tous les mots clés présents au moins 1 fois

if(preg_match_all($pattern, $txt, $resultat)){

$rMotsCles ="";//init le retour

$lResultat = count($resultat[1]);//nombre de resultats

$resultatTrie = array();//init tableau clean

for ($i=0; $i < $lResultat; $i++){
 $resultatTrie[$i] =   $resultat[1][$i];//passe les résultats dans un tableau simple
}

$resultatTrie = array_unique($resultatTrie);//enlève les doublons
$lResultatTrie = count($resultatTrie);//nbre de résultats
$nbK = 0;
foreach ($resultatTrie as $v){
$nbK++;
    $rMotsCles .= "<mot_cle_".($nbK)."><![CDATA[".$v."]]></mot_cle_".($nbK).">";//écrit le xml
}
return $rMotsCles ;
}
}


j'y reviendrais surement plus tard pour l'optimiser, mais déja ça marche
3
kohntark Messages postés 3705 Date d'inscription lundi 5 juillet 2004 Statut Membre Dernière intervention 27 avril 2012 30
23 mars 2010 à 22:32
je me mets doucement à php, et je croyais que les regex étaient la solution la plus malléable pour ce que je devais faire

Les regex sont extrêmement puissantes, mais elles consomment également beaucoup de ressources. Lorsque des fonctions natives de PHP permettent d'atteindre le même résultat il est souvent préférable de les utiliser.

correspond aux attentes et ne doit être utilisée que 2 fois par mois, donc je vais m'enn contenter

Tu as raison, inutile de se prendre la tête quant à l'optimisation dans ce cas.
Cela étant je vois 2 problèmes :
- demain ta base changera peut être de profil et tes 2-3 secondes évolueront très vite vers le + de 30 sec ... gaffe au time_limit sur lequel tu n'as peut être pas la main.
Je n'ai pas regardé mais si tu obtiens de tels temps c'est sans doute que ta variable $txt est très courte.
- lors de mes rapides tests j'ai constaté que ta fonction ne retournait pas certains mots clés, ce qui est sans doute bien plus problématique que le point précédent.
Il y a un écart de 21 résultats sur le test, ce qui est énorme (~- 50%)
Là aussi je n'ai pas pris le soin de chercher le pourquoi du comment, mais j'ai vérifié 2 mots clés qui auraient dû être retourné.

Enfin, si tu cherches des mots clés dans une base mySQL le traitement via PHP n'est sans doute pas le plus indiqué.

Bonne soirée,

Kohntark -
3
inwebo Messages postés 380 Date d'inscription lundi 12 novembre 2007 Statut Membre Dernière intervention 23 octobre 2014
21 mars 2010 à 15:45
Une remarque en passant, ne mets pas le count($resultat) dans ta boucle for à chaque passage dans cette boucle, le résultat est recalculé, déclare le avant.
0
pifethercule Messages postés 19 Date d'inscription lundi 8 février 2010 Statut Membre Dernière intervention 29 mars 2010
21 mars 2010 à 21:36
merci, j'ai bien besoin d'aide pour l'optimisation

pour ma fonction ça marche presque comme je veux, il suffit de bien lire la doc pcre...

function motsCles($keywords, $txt){
$pattern = "#(".$keywords.")+?#imU";

if(preg_match_all($pattern, $txt, $resultat)){
$rMotsCles ="";
$lResultat = count($resultat[1]);//nombre de resultats
for ($i=0; $i < $lResultat && $i<10; $i++){
    $rMotsCles .= "<mot_cle_".($i+1)."><![CDATA[".$resultat[1][$i]."]]></mot_cle_".($i+1).">";
}
return $rMotsCles ;
}
}


donc la ça me sort bien mes mots clés, petit bémol, si il est présent plusieurs fois, ça me le sort autant de fois

mes mots dans ma variable $keywords sont sous cette forme (mot1)|(mot2)|(mot3)

une idée ???
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
inwebo Messages postés 380 Date d'inscription lundi 12 novembre 2007 Statut Membre Dernière intervention 23 octobre 2014
22 mars 2010 à 09:22
Un coup de explode() sur ta variable $keywords, puis hop array_unique() ?
Cela devrait faire l'affaire, non ?
0
pifethercule Messages postés 19 Date d'inscription lundi 8 février 2010 Statut Membre Dernière intervention 29 mars 2010
22 mars 2010 à 11:11
hum...

ma variable $keyword n'a pas de doublons

c'est dans mes résultats que j'en ai, mais la je ne peux pas faire array_unique sur un tableau multidimensionnel, en tout cas si je le fais, ça me sort ensuite des undefined index...
0
pifethercule Messages postés 19 Date d'inscription lundi 8 février 2010 Statut Membre Dernière intervention 29 mars 2010
22 mars 2010 à 12:33
je vais donner un exemple plus parlant

dans ma variable $keywords, j'ai par exemple ((rack)|(rack à chandelles))

et dans mon texte "Rack à chandelles - Rack à chandelles fixes"

et je voudrais que ça me sorte

$resultat[1][0]=>rack
$resultat [1][1]=>rack à chandelles

je teste mes expressions sur ce site http://www.annuaire-info.com/outil-referencement/expression-reguliere/

et en faisant ça
((?:rack)&|(?:rack à chandelles))+?

ça me sort
Résultat : vrai
Capture 1 : Rack à chandelles
ce qui se rapproche assez du résultat voulu

mais en interne chez moi ça ne passe pas du tout...

le &| n'est pas reconnu, et en mettant juste le pipe, ça me sort

$resultat[1][0]=>rack
$resultat [1][1]=>rack

donc le "?:" avant mon mot n'est pas reconnu
0
kohntark Messages postés 3705 Date d'inscription lundi 5 juillet 2004 Statut Membre Dernière intervention 27 avril 2012 30
22 mars 2010 à 21:16
Salut Pifethercule,

J'ai peur de ne pas te suivre ... et je vais donc peut être dire des bêtises.

Pourquoi pas un truc comme ça :
<?php
function motsCle($kw, $t) {
    $aKw = explode('|',$kw);
    $aa = array();

    foreach ($aKw as $k=>$v) {
        if (false !== strposi($t, $v)) array_push($aa, '<mot_cle_'.($k+1).'><![CDATA['.$v.']]></mot_cle_'.($k+1).'>');
    }

    return implode($aa);
}
?>



Ou alors ça :
<?php
function mots1($kw, $t) {
    $aKw = explode('|',$kw);
    $aTxt = str_word_count($t, 1);
    $aRes = array_intersect($aKw, $aTxt);
    array_walk($aRes, create_function('&$v,$k', '$v = "<mot_cle_".++$k."><![CDATA[".$v."]]></mot_cle_".$k.">";'));
    return implode($aRes);
}
?>

C'est sans doute plus rapide que l'utilisation d'une regex.
Le mieux serait encore de passer un tableau comme premier argument de la fonction.

Menfin, chacune de ces fonctions (la tienne comprise) retournera des résultats différents.
Reste à voir précisément les détails de ce que tu souhaites faire (le but global, la provenance des données, la taille de ces dernières, ...)

Cordialement,

Kohntark -
0
kohntark Messages postés 3705 Date d'inscription lundi 5 juillet 2004 Statut Membre Dernière intervention 27 avril 2012 30
22 mars 2010 à 21:19
en relisant ... :
<?php
function motsCle($kw, $t) {
$aKw = explode('|',$kw);
$aa = '';

foreach ($aKw as $k=>$v) {
if (false !== strposi($t, $v)) $aa.= '<mot_cle_'.($k+1).'><![CDATA['.$v.']]></mot_cle_'.($k+1).'>';
}

return $aa;
}
?>
... j'avais cru initialement que tu retournais un tableau.


Kohntark -
0
pifethercule Messages postés 19 Date d'inscription lundi 8 février 2010 Statut Membre Dernière intervention 29 mars 2010
22 mars 2010 à 22:42
ok merci,

j'ai essayé à ta façon, mais ça ne me ressort qu'un seul mot...

et pour toutes les références de sortie un index de 155 (mon nombre de mots clés), si ça te dit quelque chose ?

de mon coté, ça me sort bien les résultats, mais j'ai des doublons
0
kohntark Messages postés 3705 Date d'inscription lundi 5 juillet 2004 Statut Membre Dernière intervention 27 avril 2012 30
22 mars 2010 à 23:47
Peut on voir comment tu implémentes ça ? Les fonctions que je proposais retournent tous les mots, sauf si j'ai loupé quelque chose.
Tu auras remarqué et corrigé mon erreur de frappe (strposi => stripos)

Peux tu poster ici les variables $keywords et $txt de ton test ?

Cordialement,

Kohntark -
0
kohntark Messages postés 3705 Date d'inscription lundi 5 juillet 2004 Statut Membre Dernière intervention 27 avril 2012 30
23 mars 2010 à 21:10
désolé kohntark, mais vu que je m'étais embarqué dans ma façon je n'ai pas trop approfondi la tienne...

C'est dommage, ça aurait peut être donné lieu à une fonction plus aboutie.


j'y reviendrais surement plus tard pour l'optimiser, mais déja ça marche

Il va falloir y penser très rapidement

J'ai fait un test rapide :
$txt = le source de la page du règlement de CS (en minuscule)

sur 1000 itérations avec 9 mots clés:
ma première fonction proposée => 2.559 s (6 résultats)
ma seconde fonction proposée => 15.14 s (6 résultats)
ta fonction => 23.107 s (5 résultats)

Avec 50 mots clés ta fonction dépasse allégrement les 2 minutes (j'ai stoppé avant)
J'ai donc baissé à 100 itérations avec 50 mots clés :
ma première fonction proposée => 0.426 s (50 résultats)
ma seconde fonction proposée => 1.532 s (50 résultats)
ta fonction => 46.228 s (29 résultats) (time_limit largement dépassé)

Je n'ai pas cherché à savoir pourquoi, mais ta fonction ne retourne pas certains mots clés, comme par exemple le mot "aide" qui est pourtant présent dans la page du règlement.

Par ailleurs, lorsque je te demandai dans mon premier message :
Reste à voir précisément les détails de ce que tu souhaites faire (le but global, la provenance des données, la taille de ces dernières, ...)

ce n'était pas pour rien. Maintenant que tu parles de mysql il y a peut être quelque chose à faire au niveau de la requête, histoire d'optimiser la chose.

Cordialement,


Kohntark -
0
pifethercule Messages postés 19 Date d'inscription lundi 8 février 2010 Statut Membre Dernière intervention 29 mars 2010
23 mars 2010 à 21:51
merci pour toutes ces infos,

je me mets doucement à php, et je croyais que les regex étaient la solution la plus malléable pour ce que je devais faire, un export d'un catalogue de produits vers un fichier xml, pour la partie de recherche et indexation de mots clés

la ce n'est qu'une petite partie de la chose, mais la totalité de l'extraction prend peu de temps 2-3s (pour plus de 500 références), correspond aux attentes et ne doit être utilisée que 2 fois par mois, donc je vais m'enn contenter

mais tout ceci m'intéresse et donc je regarderais par la suite ta proposition, je me garde ça de coté
0
pifethercule Messages postés 19 Date d'inscription lundi 8 février 2010 Statut Membre Dernière intervention 29 mars 2010
24 mars 2010 à 03:00
ok je vais faire gaffe a tout ça,

déja les fonctions de php, et aussi pour les traitements direct sur la base, mais la j'étais un peu dans l'urgence, mais dans toutes les pages que je regardais il était surtout question des différences de rapidité entre posix et pcre, du coup je n'ai pas trop regardé sur les traitements de php en lui même

par contre si tu peux me donner un exemple de mots qui ne sont pas retournés, parce que de mon coté ça marche bien, mais je n'ai pas non plus tout vérifié...

et oui la variable est assez courte (une centaine de mots a chaque fois) et je sors pas plus de 6-7 mots à chaque fois, au cas ou je sors du foreach à la dixieme itération
0
Rejoignez-nous