IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Perl Discussion :

Pourquoi mon script n'efface pas les lignes demandées


Sujet :

Langage Perl

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 299
    Points : 137
    Points
    137
    Par défaut Pourquoi mon script n'efface pas les lignes demandées
    Bonjour,

    Je dois nettoyer une base de liste de mail. J'ai donc le fichier "base_eMAILs" que je dois nettoyer en enlevant les mail qui sont dans le fichier "blacklist_eMAILs_eSAME".
    J'ai donc fait ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    #!/usr/bin/env perl 
     
    use strict; 
    use warnings; 
     
    open ( BLACK, "<blacklist_eMAILs" ) or die "unable to open file : $! \n"; 
    my @mail=<BLACK>;
     
    while ( @mail ) {
    	foreach my $mail (@mail){
    	print "FLAG email: $mail\n";
        open ( FILE, "<", "base_eMAILs" ) or die "unable to open file : $! \n"; 
        my @LINES = <FILE>; 
        close( FILE ); 
        open( FILE, ">", "base_eMAILs" ) or die "unable to open file : $! \n";
        foreach my $LINE ( @LINES ) { 
            print FILE $LINE unless ( $LINE =~ m/$mail/ ); 
        } 
        close( FILE ); 
        print( "Email $mail removed.\n" ); 
    	}
    }
    Mes flags fonctionnent mais le fichier base_eMAILs n'est pas modifié. J'ai aussi essayé une substitution par rien comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    print FILE $LINE unless ( $LINE =~ s/$mail// );
    Sans succès
    Merci de votre aide.

  2. #2
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 256
    Points
    12 256
    Billets dans le blog
    1
    Par défaut
    Bonjour,
    je ne comprends pas bien l'algo que tu as voulu implémenter, mais il est certainement inadéquat.

    Ouvrir en lecture, puis fermer, puis ouvrir en écriture, puis fermer un fichier au milieu d'une boucle while sur un autre fichier (donc pour chaque ligne de l'autre fichier), ça n'a à peu près aucune chance de marcher.

    Une solution générale pour ce genre de cas:
    - Ouverture du fichier blacklist, lecture complète et stockage dans un tableau ou plus probablement un hachage du contenu de ce fichier, fermeture de ce fichier
    - Ouverture seulement maintenant en lecture du fichier à purger, ouverture d'un second fichier en écriture (autre nom);
    - Lecture ligne à ligne du fichier à purger, écriture dans le fichier de sortie tous les enregistrements à conserver (en fonction du hachage préalablement rempli);
    - fermeture des fichiers en entrée et en sortie, renommage des fichiers pour que le fichier de sortie remplace en définitive le fichier en entrée

    Je ne peux pas entrer plus dans les détails, car tu ne donnes pas de détail. Si tu veux des détails, fournis un échantillon des deux fichiers en entrée et des critères permettant de filtrer les enregistrements à garder ou à écarter.

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 299
    Points : 137
    Points
    137
    Par défaut
    Bonjour Lolo,

    Déjà merci de m'avoir répondu...

    Je pensais être prêt de ma solution en agissant ligne par ligne car mes flags fonctionnent c'est à dire qu'ils m'affichent que les adresses mails à effacer. Mais pour répondre à ta question voici un exemple du fichier "base_eMAILs":
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    fjdjf@acme.org
    jojo@ft.com
    45689@dft.org
    dft@gg.com
    adfr@dft.com
    45698@acme.org
    4djfr@acme.com
    Voici un exemple du fichier "blacklist_eMAILs":

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    dft@gg.com
    adfr@dft.com
    Dans ce cas en FLAG j'ai donc :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    FLAG email: dft@gg.com
    Email dft@gg.com removed.
     
    FLAG email: adfr@dft.com
    Email adfr@dft.com removed.
    Donc l'idée et pour avoir de futur bon résonnement, serait d'effacer les mails qui seraient dans les fichiers "base_eMAILs" et "blacklist_eMAILs", donc de faire 2 tableaux avec les 2 fichiers et les comparer.
    Je suis dépassé.
    Merci.

  4. #4
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 299
    Points : 137
    Points
    137
    Par défaut
    En suivant le résonnement des 2 tableaux après quelques recherches motivées, j'ai trouvé ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #!/usr/bin/env perl 
    use strict; 
    use warnings; 
     
    open ( BLACK, "<blacklist_eMAILs" ) or die "unable to open file : $! \n"; 
    my @bkemails=<BLACK>;
    close (BLACK);
     
    open ( FILE, "<base_eMAILs" ) or die "unable to open file : $! \n"; 
    my @emails = <FILE>; 
    close( FILE ); 
     
    my %bkemails = map +($_ => 1), @bkemails;
    @emails = grep !$bkemails{$_}, @emails;
     
    open ( my $FILE, ">base_eMAILs" ) or die "unable to open file : $! \n";
    print $FILE "@emails";
    close $FILE;
    Cela marche sur mes 2 listes du post ci dessus avant ce dernier. Je testerai tout cela sur mon fichier réel demain.
    Si quelqu'un peut me donner un peut plus d'info sur cette ligne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    my %bkemails = map +($_ => 1), @bkemails;
    Encore merci.

  5. #5
    Expert éminent Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 035
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 035
    Points : 8 400
    Points
    8 400
    Par défaut
    salut,

    Citation Envoyé par dubis Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    my %bkemails = map +($_ => 1), @bkemails;
    @emails = grep !$bkemails{$_}, @emails;
    Si quelqu'un peut me donner un peut plus d'info sur cette ligne :
    sauf erreur, il transforme le tableau @bkemails en tableau associatif %bkemails
    map fait correspondre l'adresse email comme clé et 1 comme valeur systématique pour créer la hashtable
    c'est malin, puisque $_ dans le grep "énumère" les adresses mail une à une, et que du coup $bkemail{adresse@email} existe (ou pas)
    c'est une façon assez astucieuse de faire une intersection de tableaux

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 299
    Points : 137
    Points
    137
    Par défaut
    Merci pour toute vos réponses mais ...

    Ce qui marche pour les petits fichiers ne fonctionne pas pour les grands. Je viens donc d'appliquer le script sur mon fichier texte de 5000mails avec une "blacklist" de 2000 mails, et la liste des 5000 mails n'est pas modifiée.
    Je me demande donc ou se trouve la limite.

  7. #7
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 256
    Points
    12 256
    Billets dans le blog
    1
    Par défaut
    Avec les chiffres que tu as, tu es très très loin de la limite (qui est plutôt à plusieurs millions d'éléments, cela dépend de la mémoire dont tu disposes), et si tu l'atteignais, tu aurais une erreur de type "Out of memory" ou quelque chose comme cela.

    Je ne vois pas trop, à première vue, où ça cloche, mais je réécrirais le programme de façon un peu moins gourmande, c'est-à-dire en lisant le fichier ligne par ligne plutôt que de le "slurper" dans un tableau puis de faire une autre copie du tableau) et en utilisant un fichier de sortie distinct du fichier en entrée (sinon, si tu foires un truc, tu risques de perdre toutes tes données). Et c'est seulement quand tu es sûr que ça a bien marché que tu renommes tes fichiers.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    #!/usr/bin/env perl 
    use strict; 
    use warnings; 
     
    open my $BLACK, "<", "blacklist_eMAILs"  or die "unable to open file blacklist_eMAILs: $! \n"; 
    my @bkemails=<$BLACK>;
    close ($BLACK);
    my %bkemails = map { $_ => 1} @bkemails;
     
    open my $FILE, "<", "base_eMAILs" or die "unable to open file base_eMAILs: $! \n"; 
    open my $OUT, ">", base_eMAILs.out" or die "unable to open file : base_eMAILs.out $! \n";
    while (my $email = <$FILE>) {
         print $OUT $email unless exists $bkemails{$email};
    }
    close $FILE;
    close $OUT;
    # rename bla bla ...
    Tu peux même éviter le tableau @bkemails au début en chargeant directement le fichier BLACK dans le hachage:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    my %bkemails = map { $_ => 1} <$BLACK>;

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 299
    Points : 137
    Points
    137
    Par défaut
    Citation Envoyé par Lolo78 Voir le message
    Tu peux même éviter le tableau @bkemails au début en chargeant directement le fichier BLACK dans le hachage:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    my %bkemails = map { $_ => 1} <$BLACK>;
    Merci de ta réponse et oui mais pas n'importe où, il faut mettre cette ligne avant la ligne : "close ($BLACK);"

    J'ai testé le script. Le fichier de sortie est la copie du fichier d'entrée. Je pense qu'il y a un soucis dans cette ligne qui n'a pas d'erreur mais n'a pas de resultat non plus dans la version de Lolo:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
         print $OUT $email unless exists $bkemails{$email};
    [CODE]

    J'ai essayé une version en croisant avec mon premier post :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
             print $OUT $email unless  ($bkemails =~ m/$email/) ;
    Mais j'ai un soucis avec la variable $bkemails
    Global symbol "$bkemails" requires explicit package name at ./RemoveMail.pl line 19.
    Execution of ./RemoveMail.pl aborted due to compilation errors.
    Je l'ai donc positionné au début du script "my $bkemails;" sans effet à part plein de ligne dans le prompt.
    Use of uninitialized value $bkemails in pattern match (m//) at ./RemoveMail_Test.pl line 19, <$IN> line 5817.
    D'ailleurs ce que je ne comprend pas c'est dans mon cas je dois initialiser $bkemails car apparemment perl voit cette variable pour la première fois et dans le cas de Lolo cela n'a pas l'air de gêner le script.
    Merci

  9. #9
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 256
    Points
    12 256
    Billets dans le blog
    1
    Par défaut
    Je n'ai pas de variable $bkemails, mais une variable de hachage %bkemails, à laquelle j'accède avec la syntaxe $bkemails{$email}.

    Essaie ce script légèrement modifié (ajout de deux "chomp" pour enlever les retours à la ligne):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    #!/usr/bin/env perl 
    use strict; 
    use warnings; 
     
    open my $BLACK, "<", "blacklist_eMAILs"  or die "unable to open file blacklist_eMAILs: $! \n"; 
    my %bkemails = map { chomp; $_ => 1} <$BLACK>;
    close ($BLACK);
     
    open my $FILE, "<", "base_eMAILs" or die "unable to open file base_eMAILs: $! \n"; 
    open my $OUT, ">", base_eMAILs.out" or die "unable to open file : base_eMAILs.out $! \n";
    while (my $email = <$FILE>) {
         chomp $email;
         print $OUT $email unless exists $bkemails{$email};
    }
    close $FILE;
    close $OUT;
    Si ça ne marche toujours pas, c'est que les données ne correspondent sans doute pas exactement entre les deux fichiers. Mets alors en fichier attaché deux échantillons de tes fichiers (blacklist_eMAILs et base_eMAILs) que je puisse déboguer avec des données à peu près réelles.

  10. #10
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 299
    Points : 137
    Points
    137
    Par défaut
    Lolo avec les chomp ça ne fonctionne toujours pas

    Je viens de vérifier les fichiers avec l'éditeur "vi" et voici ce que j'ai pu observer dans mon terminale en ouvrant le fichier blacklist_emails

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    a-bc@acme.com^M
    acrpine@eole.org^M
    tellane@cc.com^M
    arichard@eciole.fr^M
    teau@toto.com^M
    nin@polibe.fr^M
    hayni@asterix.com^M
    mjahdin@asterix.com^M
    Ce "^M" n'apparait pas quand j'ouvre la liste des emails avec vi.
    Est ce que "^M" qui devrait être supprimer avec le chomp, est-il prit en compte dans perl.

    Encore merci.

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 299
    Points : 137
    Points
    137
    Par défaut
    Du coup il faut reprendre le tableau @bkemails :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #!/usr/bin/env perl 
    use strict; 
    use warnings; 
     
    my @bkemails; 
     open ( my $BLACK, "<", "blacklist_eMAILs_eSAME" ) or die "unable to open file
    blacklist_eMAILs : $! \n";
    while (my $line = <$BLACK> ){
          $line =~ s/\r?\n$//;
          push (@bkemails, $line);
    }
    close $BLACK;
     
    my %bkemails = map { chomp ;  $_ => 1} @bkemails;
     
    open ( my $IN, "<", "base_eMAILs_eSAME" ) or die "unable to open file base_eMAILs : $! \n"; 
    open ( my $OUT, ">", "base_eMAILs_eSAME_clean" ) or die "unable to write cleaned file : $! \n";
     
    while (my $email = <$IN>) {
    	  chomp $email;
    	  print $OUT ("$email \n") unless exists $bkemails{$email};
    }
    close $IN; 
    close $OUT;
    Comme ça marche et encore merci de m'avoir éclairer

  12. #12
    Rédacteur/Modérateur

    Avatar de Lolo78
    Homme Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Mai 2012
    Messages
    3 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2012
    Messages : 3 612
    Points : 12 256
    Points
    12 256
    Billets dans le blog
    1
    Par défaut
    OK, ça explique pourquoi ça ne marche pas, et je soupçonnais un truc dans ce genre, avec des caractères parasites non-imprimables, c'est pour cela que je te demandais d'attacher des fichiers..

    Les ^M, ce sont des retours à la ligne Windows; sous Unix, chomp ne va pas les reconnaître.

    Explications supplémentaire: sous Unix, un retour à la ligne c'est "\n" (caractère hexa 0A). Sous Windows, c'est deux caractères: "\r\n" (hexa 0D et 0A). Si ton fichier a été créé au format Dos/Windows et est traité par Perl sous Unix, le chomp de Perl va retirer le "\n" mais pas le "\r", car Perl ne peut pas savoir que le fichier est au format Dos. Du coup, les chaînes de caractères ne sont pas reconnues comme égales.

    Plusieurs solutions.

    Si ton éditeur de texte a cette fonction, convertir le fichier du format Dos au format Unix.

    Si ton Linux possède la fonction, utilise la fonction dos2unix à la console sur le fichier (ce qui mettra le fichier au bon format).

    Sinon, solution plus générale et plus pérenne, modifier légèrement le programme en remplaçant les deux "chomp" par s/[\r\n]+// comme indiqué ci-dessous:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    #!/usr/bin/env perl 
    use strict; 
    use warnings; 
     
    open my $BLACK, "<", "blacklist_eMAILs"  or die "unable to open file blacklist_eMAILs: $! \n"; 
    my %bkemails = map { s/[\r\n]+//; $_ => 1} <$BLACK>;
    close ($BLACK);
     
    open my $FILE, "<", "base_eMAILs" or die "unable to open file base_eMAILs: $! \n"; 
    open my $OUT, ">", base_eMAILs.out" or die "unable to open file : base_eMAILs.out $! \n";
    while (my $email = <$FILE>) {
         $email =~ s/[\r\n]+//;
         print $OUT $email unless exists $bkemails{$email};
    }
    close $FILE;
    close $OUT;

  13. #13
    Membre habitué
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    299
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 299
    Points : 137
    Points
    137
    Par défaut
    Citation Envoyé par Lolo78 Voir le message
    OK, ça explique pourquoi ça ne marche pas, et je soupçonnais un truc dans ce genre, avec des caractères parasites non-imprimables, c'est pour cela que je te demandais d'attacher des fichiers..
    Désolé mais je ne pouvais pas balancer les mails comme ça, il en a qui fonctionne encore Cependant, et de toute façon cela ne prouvera pas l'existence de ces foutus caractères car même en ayant les fichiers il n'est pas dit que ce soit effacé automatiquement par l’éditeur tel que le miens (kate)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    my %bkemails = map { s/[\r\n]+//; $_ => 1} <$BLACK>;
    Ok, sans le chomp cela m'apprendra avec la version améliorée.

    Encore merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Mon script ne garde pas les cookies, pourquoi ?
    Par Grimbot dans le forum jQuery
    Réponses: 4
    Dernier message: 30/06/2014, 09h18
  2. Pourquoi mon script ne marche pas ?
    Par chrifus dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 28/05/2008, 18h04
  3. Pourquoi mon navigateur n'exécute pas les fichiers ASP
    Par Claude_Azoulai dans le forum ASP
    Réponses: 5
    Dernier message: 21/10/2007, 17h25
  4. Pourquoi mon script ne marche pas?
    Par amarcil dans le forum Général JavaScript
    Réponses: 3
    Dernier message: 30/05/2006, 21h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo