Extraire des mots clés d'un texte [Résolu]

pifethercule 19 Messages postés lundi 8 février 2010Date d'inscription 29 mars 2010 Dernière intervention - 20 mars 2010 à 21:33 - Dernière réponse : pifethercule 19 Messages postés lundi 8 février 2010Date d'inscription 29 mars 2010 Dernière intervention
- 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
Afficher la suite 

14 réponses

Répondre au sujet
pifethercule 19 Messages postés lundi 8 février 2010Date d'inscription 29 mars 2010 Dernière intervention - 23 mars 2010 à 14:28
+3
Utile
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
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de pifethercule
kohntark 3708 Messages postés lundi 5 juillet 2004Date d'inscription 27 avril 2012 Dernière intervention - 23 mars 2010 à 22:32
+3
Utile
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 -
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de kohntark
inwebo 381 Messages postés lundi 12 novembre 2007Date d'inscription 23 octobre 2014 Dernière intervention - 21 mars 2010 à 15:45
0
Utile
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.
Commenter la réponse de inwebo
pifethercule 19 Messages postés lundi 8 février 2010Date d'inscription 29 mars 2010 Dernière intervention - 21 mars 2010 à 21:36
0
Utile
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 ???
Commenter la réponse de pifethercule
inwebo 381 Messages postés lundi 12 novembre 2007Date d'inscription 23 octobre 2014 Dernière intervention - 22 mars 2010 à 09:22
0
Utile
Un coup de explode() sur ta variable $keywords, puis hop array_unique() ?
Cela devrait faire l'affaire, non ?
Commenter la réponse de inwebo
pifethercule 19 Messages postés lundi 8 février 2010Date d'inscription 29 mars 2010 Dernière intervention - 22 mars 2010 à 11:11
0
Utile
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...
Commenter la réponse de pifethercule
pifethercule 19 Messages postés lundi 8 février 2010Date d'inscription 29 mars 2010 Dernière intervention - 22 mars 2010 à 12:33
0
Utile
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
Commenter la réponse de pifethercule
kohntark 3708 Messages postés lundi 5 juillet 2004Date d'inscription 27 avril 2012 Dernière intervention - 22 mars 2010 à 21:16
0
Utile
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 -
Commenter la réponse de kohntark
kohntark 3708 Messages postés lundi 5 juillet 2004Date d'inscription 27 avril 2012 Dernière intervention - 22 mars 2010 à 21:19
0
Utile
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 -
Commenter la réponse de kohntark
pifethercule 19 Messages postés lundi 8 février 2010Date d'inscription 29 mars 2010 Dernière intervention - 22 mars 2010 à 22:42
0
Utile
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
Commenter la réponse de pifethercule
kohntark 3708 Messages postés lundi 5 juillet 2004Date d'inscription 27 avril 2012 Dernière intervention - 22 mars 2010 à 23:47
0
Utile
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 -
Commenter la réponse de kohntark
kohntark 3708 Messages postés lundi 5 juillet 2004Date d'inscription 27 avril 2012 Dernière intervention - 23 mars 2010 à 21:10
0
Utile
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 -
Commenter la réponse de kohntark
pifethercule 19 Messages postés lundi 8 février 2010Date d'inscription 29 mars 2010 Dernière intervention - 23 mars 2010 à 21:51
0
Utile
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é
Commenter la réponse de pifethercule
pifethercule 19 Messages postés lundi 8 février 2010Date d'inscription 29 mars 2010 Dernière intervention - 24 mars 2010 à 03:00
0
Utile
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
Commenter la réponse de pifethercule

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.