...devient vite une usine a gaz surtout quand vous rechercher dans un
fichier de plusieurs milliers de lignes une centaine d'occurences
différentes.
J'ai pensé mettre mes différentes occurences dans un tableau mais je ne vois
pas comment rechercher par la suite.
Mon deuxieme souci est le temps d'execution et l'utilisation CPU/ RAM.
Je suis preneur de toutes idées et/ou direction possible.
my @mots = qw{mot1 mot2 mot3 truc bidule}; my $regexp = join("|", @mots);
attention le | coûte cher en mémoire s'il y a bcp de mots ! pensez qu'il va
rechercher chaque mot caractère par caractère, à chaque position du texte,
avant de passer au mot suivant.
En mémoire ? Plutôt en temps.
En fait cela dépend des spécifications et de la taille des données... Si on
veut trouver d'abord le premier mot (n'importe où) et ne chercher les suivants
que si le premier n'est pas trouvé, la méthode de la regexp ne marche pas.
Sinon, ça marche bien surtout si on fabrique une regexp optimisée en triant
les mots par racine commune. Il y des méthodes pour faire cela.
On peut aussi améliorer le comportement des regexp en ne compilant l'expression régulière qu'une seule fois...
Je n'avais pas pensé à ça dans mon exemple :) Mais je pense que la tâche d'automatisation risque d'être lourde si je tente d'encapsuler les racines communes à la volée... Mais peut-être celà serait-il plus facilement faisable en encapsulant les racines lettres par lettres
Julien
regexp :
my @mots = qw{mot1 mot2 mot3 truc bidule};
my $regexp = join("|", @mots);
attention le | coûte cher en mémoire s'il y a bcp de mots ! pensez qu'il
va
rechercher chaque mot caractère par caractère, à chaque position du
texte,
avant de passer au mot suivant.
En mémoire ? Plutôt en temps.
En fait cela dépend des spécifications et de la taille des données... Si
on
veut trouver d'abord le premier mot (n'importe où) et ne chercher les
suivants
que si le premier n'est pas trouvé, la méthode de la regexp ne marche pas.
Sinon, ça marche bien surtout si on fabrique une regexp optimisée en
triant
les mots par racine commune. Il y des méthodes pour faire cela.
On peut aussi améliorer le comportement des regexp en ne compilant
l'expression régulière qu'une seule fois...
Je n'avais pas pensé à ça dans mon exemple :)
Mais je pense que la tâche d'automatisation risque d'être lourde si je tente
d'encapsuler les racines communes à la volée...
Mais peut-être celà serait-il plus facilement faisable en encapsulant les
racines lettres par lettres
my @mots = qw{mot1 mot2 mot3 truc bidule}; my $regexp = join("|", @mots);
attention le | coûte cher en mémoire s'il y a bcp de mots ! pensez qu'il va
rechercher chaque mot caractère par caractère, à chaque position du texte,
avant de passer au mot suivant.
En mémoire ? Plutôt en temps.
En fait cela dépend des spécifications et de la taille des données... Si on
veut trouver d'abord le premier mot (n'importe où) et ne chercher les suivants
que si le premier n'est pas trouvé, la méthode de la regexp ne marche pas.
Sinon, ça marche bien surtout si on fabrique une regexp optimisée en triant
les mots par racine commune. Il y des méthodes pour faire cela.
On peut aussi améliorer le comportement des regexp en ne compilant l'expression régulière qu'une seule fois...
Je n'avais pas pensé à ça dans mon exemple :) Mais je pense que la tâche d'automatisation risque d'être lourde si je tente d'encapsuler les racines communes à la volée... Mais peut-être celà serait-il plus facilement faisable en encapsulant les racines lettres par lettres
Julien
Laurent Wacrenier
Fabrice L. écrit:
je recherche dans un fichier plusieurs mots (il peut y en avoir des centaines)
Met les mots dans un hash et lit le fichier mot par mot, ou ligne par ligne et découpe les lignes en mots :
my %h = map { $_ => 1 } qw/titi toto tata/;
while(<>) { print if grep { $h{$_} } split " "; }
Fabrice L. <rafale@altern.org> écrit:
je recherche dans un fichier plusieurs mots (il peut y en avoir des
centaines)
Met les mots dans un hash et lit le fichier mot par mot, ou ligne par
ligne et découpe les lignes en mots :
next if (!$liste_moteurs[$_][0]); if ($elements[9] =~ /$liste_moteurs[$_][0]/) { $elements[9] =~ /$liste_moteurs[$_][1]s*([^&;]+)/i; $or{$1}++; } }
et tout fonctionne parfaitement tout betement.
Fabrice
"Fabrice L." a écrit dans le message news: cb77e6$if2$
Merci à tous pour vos réponses :
Antoine Dinimant
En fait cela dépend des spécifications et de la taille des données... Si on veut trouver d'abord le premier mot (n'importe où) et ne chercher les suivants que si le premier n'est pas trouvé, la méthode de la regexp ne marche pas.
Si. Les moteurs de regex POSIX testent tous les termes de l'alternative afin de recherche la plus longue correspondance, mais le moteur de Perl n'est pas POSIX. Tu peux le vérifier ainsi :
'toto une titi' =~ /(un|une)/ ; print $1 ;
cf. l'excellentissime Friedl, Maîtrise des expressions régulières, chez O'Reilly
En fait cela dépend des spécifications et de la taille des données... Si on
veut trouver d'abord le premier mot (n'importe où) et ne chercher les suivants
que si le premier n'est pas trouvé, la méthode de la regexp ne marche pas.
Si. Les moteurs de regex POSIX testent tous les termes de l'alternative
afin de recherche la plus longue correspondance, mais le moteur de Perl
n'est pas POSIX. Tu peux le vérifier ainsi :
'toto une titi' =~ /(un|une)/ ;
print $1 ;
cf. l'excellentissime Friedl, Maîtrise des expressions régulières, chez
O'Reilly
En fait cela dépend des spécifications et de la taille des données... Si on veut trouver d'abord le premier mot (n'importe où) et ne chercher les suivants que si le premier n'est pas trouvé, la méthode de la regexp ne marche pas.
Si. Les moteurs de regex POSIX testent tous les termes de l'alternative afin de recherche la plus longue correspondance, mais le moteur de Perl n'est pas POSIX. Tu peux le vérifier ainsi :
'toto une titi' =~ /(un|une)/ ; print $1 ;
cf. l'excellentissime Friedl, Maîtrise des expressions régulières, chez O'Reilly
Antoine Dinimant
Il faut maintenant décortiquer la fonction index() pour savoir si elle construit une Rx ;o)
Elle ne le fait pas. La première des recommandations d'optimisation des regex, c'est "si vous le pouvez, oubliez-nous et utilisez index".
Il faut maintenant décortiquer la fonction index() pour savoir si elle
construit une Rx ;o)
Elle ne le fait pas. La première des recommandations d'optimisation des
regex, c'est "si vous le pouvez, oubliez-nous et utilisez index".
je confirme l'impression que me laissait ton premier message : tu n'as absolument pas besoin de regex pour ça, index suffit largement !
(mais pense à enlever le devant le .)
Gaëtan Duchaussois
le Mon, 21 Jun 2004 17:16:48 +0200, Fabrice L. a ressenti le besoin de nous dire:
Bonjour,
je recherche dans un fichier plusieurs mots (il peut y en avoir des centaines)
sinon en complément aux autres réponses si tu veux un truc vraiment optimisé tu dois pouvoir implémenter l'algorithme de aho-corasick en perl, mais je ne sais pas si ça vaut l'investissement...
Je suis preneur de toutes idées et/ou direction possible.
Mon idée est un peu tordu je l'avoue mais ça doit pouvoir être ce qui mouline le moins... L'algo est celui utilisé par agrep.
le Mon, 21 Jun 2004 17:16:48 +0200, Fabrice L. a ressenti le besoin de nous dire:
Bonjour,
je recherche dans un fichier plusieurs mots (il peut y en avoir des
centaines)
sinon en complément aux autres réponses si tu veux un truc vraiment
optimisé tu dois pouvoir implémenter l'algorithme de aho-corasick en
perl, mais je ne sais pas si ça vaut l'investissement...
Je suis preneur de toutes idées et/ou direction possible.
Mon idée est un peu tordu je l'avoue mais ça doit pouvoir être ce qui
mouline le moins... L'algo est celui utilisé par agrep.
le Mon, 21 Jun 2004 17:16:48 +0200, Fabrice L. a ressenti le besoin de nous dire:
Bonjour,
je recherche dans un fichier plusieurs mots (il peut y en avoir des centaines)
sinon en complément aux autres réponses si tu veux un truc vraiment optimisé tu dois pouvoir implémenter l'algorithme de aho-corasick en perl, mais je ne sais pas si ça vaut l'investissement...
Je suis preneur de toutes idées et/ou direction possible.
Mon idée est un peu tordu je l'avoue mais ça doit pouvoir être ce qui mouline le moins... L'algo est celui utilisé par agrep.
À (at) Tue, 22 Jun 2004 00:26:54 +0200, Antoine Dinimant écrivait (wrote):
En fait cela dépend des spécifications et de la taille des données... Si on veut trouver d'abord le premier mot (n'importe où) et ne chercher les suivants que si le premier n'est pas trouvé, la méthode de la regexp ne marche pas.
Si. Les moteurs de regex POSIX testent tous les termes de l'alternative afin de recherche la plus longue correspondance, mais le moteur de Perl n'est pas POSIX. Tu peux le vérifier ainsi :
'toto une titi' =~ /(un|une)/ ; print $1 ;
cf. l'excellentissime Friedl, Maîtrise des expressions régulières, chez O'Reilly
Votre remarque n'est vrai que pour un ancrage donné (un moteur POSIX afficherait 'une' alors que perl affiche bien 'un').
Ceci étant, regardez l'exemple suivant :
'court et longueur' =~ m/(longueur|court)/; print $1;
C'est bien 'court' qui est trouvé en premier : la regex est reconnue au plus tôt (ceci est vrai que le moteur soit POSIX ou Perl). Le recherche de la regex la plus longue dans le cas d'une alternative (ce qui est fait en POSIX et non en Perl) n'a lieu qu'à un ancrage donné.
Donc le code :
while (<>) { if (m/(longueur|court)/) { print "$1 -> $_"; } }
N'est pas exactement équivalent à :
while (<>) { if (m/longueur/) { print "longueur -> $_"; } elsif (m/court/) { print "court -> $_"; } }
(Si on reçoit une ligne contenant "court" avant "longueur"...)
Si vous voulez en savoir plus sur les regex, il y a effectivement le livre que vous citez mais aussi toute la documentation qui vient avec Perl. Elle existe même en français :
-- Paul Gaborit - <http://www.enstimac.fr/~gaborit/> Perl en français - <http://www.enstimac.fr/Perl/>
À (at) Tue, 22 Jun 2004 00:26:54 +0200,
Antoine Dinimant <antoun_SANS_CA_@free.fr> écrivait (wrote):
En fait cela dépend des spécifications et de la taille des données... Si on
veut trouver d'abord le premier mot (n'importe où) et ne chercher les
suivants que si le premier n'est pas trouvé, la méthode de la regexp ne
marche pas.
Si. Les moteurs de regex POSIX testent tous les termes de l'alternative afin
de recherche la plus longue correspondance, mais le moteur de Perl n'est pas
POSIX. Tu peux le vérifier ainsi :
'toto une titi' =~ /(un|une)/ ;
print $1 ;
cf. l'excellentissime Friedl, Maîtrise des expressions régulières, chez
O'Reilly
Votre remarque n'est vrai que pour un ancrage donné (un moteur POSIX
afficherait 'une' alors que perl affiche bien 'un').
Ceci étant, regardez l'exemple suivant :
'court et longueur' =~ m/(longueur|court)/;
print $1;
C'est bien 'court' qui est trouvé en premier : la regex est reconnue au plus
tôt (ceci est vrai que le moteur soit POSIX ou Perl). Le recherche de la
regex la plus longue dans le cas d'une alternative (ce qui est fait en POSIX
et non en Perl) n'a lieu qu'à un ancrage donné.
Donc le code :
while (<>) {
if (m/(longueur|court)/) {
print "$1 -> $_";
}
}
N'est pas exactement équivalent à :
while (<>) {
if (m/longueur/) {
print "longueur -> $_";
} elsif (m/court/) {
print "court -> $_";
}
}
(Si on reçoit une ligne contenant "court" avant "longueur"...)
Si vous voulez en savoir plus sur les regex, il y a effectivement le livre
que vous citez mais aussi toute la documentation qui vient avec Perl. Elle
existe même en français :
À (at) Tue, 22 Jun 2004 00:26:54 +0200, Antoine Dinimant écrivait (wrote):
En fait cela dépend des spécifications et de la taille des données... Si on veut trouver d'abord le premier mot (n'importe où) et ne chercher les suivants que si le premier n'est pas trouvé, la méthode de la regexp ne marche pas.
Si. Les moteurs de regex POSIX testent tous les termes de l'alternative afin de recherche la plus longue correspondance, mais le moteur de Perl n'est pas POSIX. Tu peux le vérifier ainsi :
'toto une titi' =~ /(un|une)/ ; print $1 ;
cf. l'excellentissime Friedl, Maîtrise des expressions régulières, chez O'Reilly
Votre remarque n'est vrai que pour un ancrage donné (un moteur POSIX afficherait 'une' alors que perl affiche bien 'un').
Ceci étant, regardez l'exemple suivant :
'court et longueur' =~ m/(longueur|court)/; print $1;
C'est bien 'court' qui est trouvé en premier : la regex est reconnue au plus tôt (ceci est vrai que le moteur soit POSIX ou Perl). Le recherche de la regex la plus longue dans le cas d'une alternative (ce qui est fait en POSIX et non en Perl) n'a lieu qu'à un ancrage donné.
Donc le code :
while (<>) { if (m/(longueur|court)/) { print "$1 -> $_"; } }
N'est pas exactement équivalent à :
while (<>) { if (m/longueur/) { print "longueur -> $_"; } elsif (m/court/) { print "court -> $_"; } }
(Si on reçoit une ligne contenant "court" avant "longueur"...)
Si vous voulez en savoir plus sur les regex, il y a effectivement le livre que vous citez mais aussi toute la documentation qui vient avec Perl. Elle existe même en français :
je confirme l'impression que me laissait ton premier message : tu n'as absolument pas besoin de regex pour ça, index suffit largement !
(mais pense à enlever le devant le .)
Sur cette dernière remarque, je suis d'accord. Le . est totalement inutile dans une chaîne de caractères normales.
En revanche, une regexp pourrait être très efficace à condition de la construire intelligement (ce qui n'est pas faisable facilement automatiquement). :
%iso_to_name ( be => "Google Belgique", ch => "Google Suisse", fr => "Google France", de => "Google Allemagne", # etc. );
if ($log =~ m/google.(be|ch|fr|de)/) { print "from $iso_to_name{$1}n"; }
C'est certainement plus efficace que plusieurs appels successifs à index... La construction est ici facile parce que tout commence par 'google.'. Évidemment, si il y a d'autre moteurs, l'expression rationnelle (ou régulière) n'est plus aussi simple. Et la mise en facteur de 'google.' devrait être automatisé... C'est cela qui n'est pas trivial.
-- Paul Gaborit - <http://www.enstimac.fr/~gaborit/> Perl en français - <http://www.enstimac.fr/Perl/>
À (at) Tue, 22 Jun 2004 00:30:50 +0200,
Antoine Dinimant <antoun_SANS_CA_@free.fr> écrivait (wrote):
je confirme l'impression que me laissait ton premier message : tu n'as
absolument pas besoin de regex pour ça, index suffit largement !
(mais pense à enlever le devant le .)
Sur cette dernière remarque, je suis d'accord. Le . est totalement inutile
dans une chaîne de caractères normales.
En revanche, une regexp pourrait être très efficace à condition de la
construire intelligement (ce qui n'est pas faisable facilement
automatiquement). :
%iso_to_name (
be => "Google Belgique",
ch => "Google Suisse",
fr => "Google France",
de => "Google Allemagne",
# etc.
);
if ($log =~ m/google.(be|ch|fr|de)/) {
print "from $iso_to_name{$1}n";
}
C'est certainement plus efficace que plusieurs appels successifs à index... La
construction est ici facile parce que tout commence par 'google.'. Évidemment,
si il y a d'autre moteurs, l'expression rationnelle (ou régulière) n'est plus
aussi simple. Et la mise en facteur de 'google.' devrait être
automatisé... C'est cela qui n'est pas trivial.
--
Paul Gaborit - <http://www.enstimac.fr/~gaborit/>
Perl en français - <http://www.enstimac.fr/Perl/>
je confirme l'impression que me laissait ton premier message : tu n'as absolument pas besoin de regex pour ça, index suffit largement !
(mais pense à enlever le devant le .)
Sur cette dernière remarque, je suis d'accord. Le . est totalement inutile dans une chaîne de caractères normales.
En revanche, une regexp pourrait être très efficace à condition de la construire intelligement (ce qui n'est pas faisable facilement automatiquement). :
%iso_to_name ( be => "Google Belgique", ch => "Google Suisse", fr => "Google France", de => "Google Allemagne", # etc. );
if ($log =~ m/google.(be|ch|fr|de)/) { print "from $iso_to_name{$1}n"; }
C'est certainement plus efficace que plusieurs appels successifs à index... La construction est ici facile parce que tout commence par 'google.'. Évidemment, si il y a d'autre moteurs, l'expression rationnelle (ou régulière) n'est plus aussi simple. Et la mise en facteur de 'google.' devrait être automatisé... C'est cela qui n'est pas trivial.
-- Paul Gaborit - <http://www.enstimac.fr/~gaborit/> Perl en français - <http://www.enstimac.fr/Perl/>
Fabrice L.
Évidemment, si il y a d'autre moteurs, l'expression rationnelle (ou régulière) n'est plus
aussi simple. Et la mise en facteur de 'google.' devrait être automatisé... C'est cela qui n'est pas trivial.
Et c'est bien la mon probleme. car si il n'y a pas que google, ca va coincer.
foreach (@F) { my @elements = split '|', $_; next if (!$elements[9]);
for (0..$nombre_de_moteurs) {
next if (!$liste_moteurs[$_][0]);
if ($elements[9] =~ /$liste_moteurs[$_][0]/) $or{$liste_moteurs[$_][2]}++;} } }
foreach $moteur ( sort sort_or keys %or) { next if (!$moteur); print "$moteur $or{$moteur}<BR>"; }
sub sort_or { ... ####
ce script la est tres lent avec quasi 100% d'utilisation CPU (10/12sec. ) sur un fichier de 18000 lignes ( c vrai que pour chaque ligne il faut tester les 200 moteurs) alors que ...
## script2.pl
open F, "$dir_fichier"; @F = <F>; close F;
foreach (@F) { my @elements = split '|', $_; next if (!$elements[9]);
foreach $moteur ( sort sort_or keys %or) { next if (!$moteur); print "$moteur $or{$moteur}<BR>"; }
sub sort_or { ... ####
...prends a peine 5 secondes sans occuper le CPU a plein régime...
Par contre je préfere le script1 pour des raisons pratiques , en travaillant avec une liste de liste je peux travailler ET sur le moteur ET sur les mots-clés alors qu'avec le script2 c soit l'un soit l'autre...
N'y a t-il pas moyen d'optimiser le script1 ?
Fabrice
Évidemment,
si il y a d'autre moteurs, l'expression rationnelle (ou régulière) n'est
plus
aussi simple. Et la mise en facteur de 'google.' devrait être
automatisé... C'est cela qui n'est pas trivial.
Et c'est bien la mon probleme. car si il n'y a pas que google, ca va
coincer.
foreach (@F) {
my @elements = split '|', $_;
next if (!$elements[9]);
for (0..$nombre_de_moteurs) {
next if (!$liste_moteurs[$_][0]);
if ($elements[9] =~ /$liste_moteurs[$_][0]/)
$or{$liste_moteurs[$_][2]}++;}
}
}
foreach $moteur ( sort sort_or keys %or) {
next if (!$moteur);
print "$moteur $or{$moteur}<BR>";
}
sub sort_or {
...
####
ce script la est tres lent avec quasi 100% d'utilisation CPU (10/12sec. )
sur un fichier de 18000 lignes ( c vrai que pour chaque ligne il faut tester
les 200 moteurs) alors que ...
## script2.pl
open F, "$dir_fichier";
@F = <F>;
close F;
foreach (@F) {
my @elements = split '|', $_;
next if (!$elements[9]);
foreach $moteur ( sort sort_or keys %or) {
next if (!$moteur);
print "$moteur $or{$moteur}<BR>";
}
sub sort_or {
...
####
...prends a peine 5 secondes sans occuper le CPU a plein régime...
Par contre je préfere le script1 pour des raisons pratiques , en travaillant
avec une liste de liste je peux travailler ET sur le moteur ET sur les
mots-clés alors qu'avec le script2 c soit l'un soit l'autre...
foreach (@F) { my @elements = split '|', $_; next if (!$elements[9]);
for (0..$nombre_de_moteurs) {
next if (!$liste_moteurs[$_][0]);
if ($elements[9] =~ /$liste_moteurs[$_][0]/) $or{$liste_moteurs[$_][2]}++;} } }
foreach $moteur ( sort sort_or keys %or) { next if (!$moteur); print "$moteur $or{$moteur}<BR>"; }
sub sort_or { ... ####
ce script la est tres lent avec quasi 100% d'utilisation CPU (10/12sec. ) sur un fichier de 18000 lignes ( c vrai que pour chaque ligne il faut tester les 200 moteurs) alors que ...
## script2.pl
open F, "$dir_fichier"; @F = <F>; close F;
foreach (@F) { my @elements = split '|', $_; next if (!$elements[9]);
foreach $moteur ( sort sort_or keys %or) { next if (!$moteur); print "$moteur $or{$moteur}<BR>"; }
sub sort_or { ... ####
...prends a peine 5 secondes sans occuper le CPU a plein régime...
Par contre je préfere le script1 pour des raisons pratiques , en travaillant avec une liste de liste je peux travailler ET sur le moteur ET sur les mots-clés alors qu'avec le script2 c soit l'un soit l'autre...