probleme dans le resultats d'un script qui cherche de mots - Perl - Programmation
Marsh Posté le 10-05-2016 à 18:31:55
debut25 a écrit : |
Avec ces infos difficilement... Faut nous montrer le code (entre balises) et un exemple de texte pour pouvoir reproduire le problème.
Marsh Posté le 10-05-2016 à 19:23:25
Les textes sont en italien,
je vous en écris un exemple:
162545185920778240 Governo Monti: decreto in cdm per approvazione! http://fb.me/1bj50bZI9
192902763032743936 #Ferrara critica #Grillo perché dice cose che dicevano Berlusconi e Bossi. E che non hanno fatto.
195604733296254977 #Grillo contro #Napolitano: "Presidente della Repubblica? No, presidente dei partiti" http://video.repubblica.it/edizion [...] 69?ref=twh …
avec la premiere partie du script on ouvre un fichier qui contient la tokenisation de textes et chaque mot est mit dans un array (dans ce cas @forme)
"
my $i=0;
my $mot_trouv=0;
for ($forme[$i] = 0; $i <= $#forme; $i++){ #on commence le boucle pour la recherche
if ($forme[$i] =~ /^\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d$/){ # on cherche le numero identifiant
if ($i <= $#forme){ # et chaque fois qu on le trouve on affiche les resultats oui/no
if ($mot_trouv ne 0){
print OUT "\"", $forme[$i], "\"", ",\t\"1\"", "\n";
}
else {
print OUT "\"", $forme[$i], "\"", ",\t\"0\"", "\n";
}
$mot_trouv=0;
$i++;
}
}
elsif ($forme[$i] eq "Governo" ){ #mot cherché "Governo"
$mot_trouv++;
}
}
close OUT;
"
les resultats de ce script sont
"192902763032743936", "1"
"195604733296254977", "0"
comme on peut voir le premier il est pas affiché et son resultat est affiché à coté du deuxieme
quel est l'erreur?
merci pour votre disponibilité
Marsh Posté le 10-05-2016 à 19:43:13
> for ($forme[$i] = 0; $i <= $#forme; $i++)
1) ça devrait pas être for ($i = 0; $i <= $#forme; $i++) plutôt?
Et je vois pas ce que vient faire ce test
> if ($i <= $#forme)
vu que c'est implicite avec la condition de boucle for ($forme[$i] = 0; $i <= $#forme;...
Et je comprends pas non plus ce test
> if ($mot_trouv ne 0)
vu que tu compares une valeur numérique 0 avec le comparateur de chaînes "ne"
C'est pas simplement
if ($mot_trouv) { c'est à dire if ($mot_trouv != 0) { que tu veux?
2) et ça serait pas plus simple avec un foreach?
foreach (@forme) {
if (/^\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d$/) {
....
A+,
Marsh Posté le 10-05-2016 à 20:10:40
Je vous remercie pour vos conseils,
en modifiant le script comme suivant:
my $i=0;
my $mot_trouv=0;
foreach (@forme){
if ($forme[$i] =~ /^\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d$/){ # on cherche le numero identifiant
if ($mot_trouv){
print OUT "\"", $forme[$i], "\"", ",\t\"1\"", "\n";
}
else {
print OUT "\"", $forme[$i], "\"", ",\t\"0\"", "\n";
}
$mot_trouv=0;
}
elsif ($forme[$i] eq "Governo" ){ #mot cherché "Governo"
$mot_trouv++;
}
$i++
}
close OUT;
j'ai comme resultats:
"162545185920778240", "0"
"192902763032743936", "1"
"195604733296254977", "0"
avec le meme probleme que avant
Merci encore
Marsh Posté le 11-05-2016 à 01:19:08
(Dans les forum je tutoie - libre à toi bien sûr de faire de même.)
Tu peux montrer la première partie du script? (Entre parenthèses, faut toujours donner le script complet pour faciliter la vie aux gens qui veulent bien aider...) Sous quelle forme exactement tu reçois les textes, un texte par ligne? Parce que ça serait bien plus élégant à traiter...
Le problème est que quand on rencontre un identifiant (numéro) il ne faut pas imprimer cet identifiant et le résultat mais l'identifiant d'avant (car c'est pour celui-là que le résultat est vrai). J'ai corrigé ton script en gardant la logique du code (et modifié quelque détails en passant), ça fonctionne mais c'est vraiment moche...
(Pour la prochaine fois, le code entre balises [ code=perl] script ici [ /code] (sans les espaces) c'est bien plus lisible.)
Code :
|
Si jamais il est possible de récupérer les articles ligne par ligne voici ma version que je trouve bien plus propre:
Code :
|
Par contre il reste un problème: Quand on cherche p.ex. "Napolitano" on ne trouvera rien avec ce script - parce que dans le texte c'est marqué "#Napolitano:". Je propose donc de "nettoyer" chaque mot avant la comparaison avec un truc genre $mot=~s/[:!#.;"?,]//g;.
Marsh Posté le 11-05-2016 à 01:26:37
Un truc de ce genre devrait faire ce que vous voulez.
Code :
|
EDIT: ah je vois que RdC avait déjà répondu une solution similaire
A+,
Marsh Posté le 11-05-2016 à 01:36:26
Et en intégrant le préambule de RdC pour tester
Code :
|
"162545185920778240", "0" |
Citation : Par contre il reste un problème: Quand on cherche p.ex. "Napolitano" on ne trouvera rien avec ce script - parce que dans le texte c'est marqué "#Napolitano:". Je propose donc de "nettoyer" chaque mot avant la comparaison avec un truc genre $mot=~s/[:!#.;"?,]//g;. |
d'ou mon split sur les frontières de mot, avec \b (qui marche pas avec les mots composés je crois mais permet néanmoins de faire un rapide test ici)
A+,
Marsh Posté le 11-05-2016 à 01:44:49
Citation : EDIT: ah je vois que RdC avait déjà répondu une solution similaire |
J'ai été plus rapide mais tu as fait plus élégant.
gilou a écrit :
|
Merci, je ne connaissais pas.
edit: L'utilisation de \b introduit un comportement qui peut être un bug: On retrouve dans la liste des mots aussi les mots qui se trouvent dans d'éventuells liens - autrement dit si j'ai dans le premier article un lien avec une adresse genre http://Grillo.Machin.Chose.it j'aurai $mot_trouv=1. A voir si c'est un problème (je dis ça si le TO veut réutiliser \b).
Marsh Posté le 11-05-2016 à 02:32:48
> L'utilisation de \b introduit un comportement qui peut être un bug...
Ce pourquoi j'ai dit que c'était utile pour une procédure de test rapide. Mais comme il a déjà écrit un tokenizer, ça n'a pas d'importance pour lui, il suffit qu'il le réutilise pour construire sa liste de tokens.
De toute façon, ce n'est pas ainsi qu'il faut traiter ce type de problème si on veut être efficace et que l'on a pas mal de lignes:
Il faut faire un hash dont les clés sont les mots et les valeurs, un array contenant les numéros de ligne contenant le mot.
Ainsi, tout est fait en une fois et on ne rescanne pas toutes les lignes à chaque recherche de mot.
Code :
|
Napolitano: |
On peut simplifier l'écriture avec les smartmatches:
Code : |
mais je ne suis pas sur que ce soit plus efficace.
A+,
Marsh Posté le 11-05-2016 à 09:40:03
je vous remercie pour vos conseils! et pour tous les infos! ça m'aide beaucoup!!! mercie encore et bonne journée!
Marsh Posté le 11-05-2016 à 15:53:19
Noter que pour le tokenizer, comme on a des mots avec accents (qui plaisent pas au split /\b/ on peut faire
foreach (split(/[^\p{L}\p{N}'-]+/)) {
On splitte sur tout ce qui n'est pas une lettre, un chiffre (tous deux, au sens unicode), ' ou -.
On peut même améliorer avec
use Lingua::StopWords qw( getStopWords );
my $stopwords = getStopWords('it');
foreach (grep(!$stopwords->{lc($_)}, split(/[^\p{L}\p{N}'-]+/))) {
si on veut éliminer les mots sans importance les plus courants (ça vire "perché" et "E" ici par exemple)
Bref, un
my $text =<<END;
162545185920778240 Governo Monti: decreto in cdm per approvazione! http://fb.me/1bj50bZI9
192902763032743936 #Ferrara critica #Grillo perché dice cose che dicevano Berlusconi e Bossi. E che non hanno fatto.
195604733296254977 #Grillo contro #Napolitano: "Presidente della Repubblica? No, presidente dei partiti
END
$text =~ s#(https?://\S+?)(\.?\s)##igs;
foreach (grep(!$stopwords->{lc($_)}, split(/[^\p{L}\p{N}'-]+/, $text))) {
....
ça tokenize comme suit
162545185920778240
Governo
Monti
decreto
cdm
approvazione
192902763032743936
Ferrara
critica
Grillo
dice
cose
dicevano
Berlusconi
Bossi
fatto
195604733296254977
Grillo
Napolitano
Presidente
Repubblica
No
presidente
partiti
ce qui me semble assez clean, après, on peut affiner au vu de son input.
A+,
Marsh Posté le 10-05-2016 à 16:42:12
Bonjour
je suis debutant en perl et j'ai de soucis par rapport aux resultats de mon script.
c'est un script qui recherche de mots dans plusieurs textes et chaque textes est identifié par un numero (ex: 2563).
Après avoir tokenisé les textes j'ai analisé chaque mot (maintenant dans un array) avec un boucle for.
le fiche de resultats doit contenir le numero identifiant de chaque textes et à coté une decision oui/no (1/0) si les mots cherchés on les a trouvés dans le texte.
le script repere tres bien les mots mais affiche mal les resultats:
si l'identifiant n° 2563 contient les mots cherchés
dans le fiche de resultats il affiche 2563 0
et le suivant id 2564 avec le resultat du premier (dans ce cas 1):
du coup on a 2563 0
2564 1
J'espère que quelqu un peut m'aider
dans tout cas merci!