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 :

supprimer les doublons d'un fichier


Sujet :

Langage Perl

  1. #1
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    624
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 624
    Points : 69
    Points
    69
    Par défaut supprimer les doublons d'un fichier
    Bonjour,

    Cette commande me permet de retirer les doublons dans un fichier à partir de la ligne de commande Perl.
    perl -ne "print if ! $lignes{$_}++" New_2014.txt > toto

    Mais je voudrais avoir le même résultat à partir d'un script Perl (.pl).

    Comment puis je faire ?

    Merci pour votre aide.

  2. #2
    Membre habitué
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juillet 2014
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2014
    Messages : 84
    Points : 197
    Points
    197
    Par défaut
    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
    use strict;
    use warnings;
     
    my $fichier_in;
    my $fichier_out;
    my %lignes = ();
     
     
    $fichier_in = "toto.txt";
    $fichier_out = "toto_out.txt";
     
    open( IN , "<$fichier_in" ) or die( "Can't open $fichier_in : $!");
    open( OUT , ">$fichier_out" ) or die( "Can't open $fichier_out : $!");
     
    while( <IN> ){
      if ( ! exists( $lignes{$_}) ){
        print OUT $_;
      }
      $lignes{$_}++;
    }
     
    close( IN );
    close( OUT );
    à tester, aucune garantie de résultat.

  3. #3
    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 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    @JeanMi3000: Bonjour, le code que tu as posté devrait fonctionner pour le dédoublonnage d'un fichier, mais il ne respecte pas les "bonnes pratiques" communément admises de nos jours (depuis une dizaine d'années, tout de même) dans la communauté Perl.

    - Utiliser des file handles lexicaux (et non des "barewords");
    - Utiliser la syntaxe à trois arguments de la fonction open.

    Ce qui donne par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    open my $IN , "<", $fichier_in or die "Can't open $fichier_in : $!";
    Cela implique évidemment de modifier aussi la boucle pour qu'elle l'utilise le descripteur lexical.:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    while( <$IN> ){ # ...

  4. #4
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    624
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 624
    Points : 69
    Points
    69
    Par défaut
    Donc si je comprends bien, ça donne :

    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
    25
     
     
    234567891011121314151617181920212223 use strict;
    use warnings;
     
    my $fichier_in;
    my $fichier_out;
    my %lignes = ();
     
     
    $fichier_in = "toto.txt";
    $fichier_out = "toto_out.txt";
     
    open my $IN , "<", $fichier_in or die "Can't open $fichier_in : $!";
    open( OUT , ">$fichier_out" ) or die( "Can't open $fichier_out : $!");
     
    while( <$IN> ){
      if ( ! exists( $lignes{$_}) ){
        print OUT $_;
      }
      $lignes{$_}++;
    }
     
     
    close( OUT );

    Par contre pour le fichier OUT, on le gére comment ?

    Merci pour votre aide

  5. #5
    Membre habitué
    Homme Profil pro
    Ingénieur intégration
    Inscrit en
    Juillet 2014
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur intégration
    Secteur : Conseil

    Informations forums :
    Inscription : Juillet 2014
    Messages : 84
    Points : 197
    Points
    197
    Par défaut
    Citation Envoyé par Lolo78 Voir le message
    @JeanMi3000: Bonjour, le code que tu as posté devrait fonctionner pour le dédoublonnage d'un fichier, mais il ne respecte pas les "bonnes pratiques" communément admises de nos jours (depuis une dizaine d'années, tout de même) dans la communauté Perl.

    - Utiliser des file handles lexicaux (et non des "barewords");
    - Utiliser la syntaxe à trois arguments de la fonction open.
    noté
    ça me fout 'les boules' car j'ai appris à coder en perl grâce à ce site
    bref, je vais tacher de changer ma façon de faire.

    Citation Envoyé par vince2005 Voir le message
    Donc si je comprends bien, ça donne :

    Par contre pour le fichier OUT, on le gére comment ?

    Merci pour votre aide
    comme pour le fichier IN, il suffit de remplacer le bareword OUT par une variable à créer nommée $OUT.

  6. #6
    Membre du Club
    Inscrit en
    Mars 2006
    Messages
    624
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 624
    Points : 69
    Points
    69
    Par défaut
    Enfin sur le fond, ça ne change absolument rien !

    il n'y a que sur la forme...c'est pas un peu commerciale, ça ??

    D'ailleurs ça rend le code moins lisible : mais c'es mon avis !

  7. #7
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Citation Envoyé par JeanMi3000 Voir le message
    comme pour le fichier IN, il suffit de remplacer le bareword OUT par une variable à créer nommée $OUT.
    Attention cependant, pour éviter les ambiguité liées à la syntaxe de print, il faut, lorsque le filehandle n'est pas une bareword, le spécifier entre accolade (ou précédé du signe + pour forcer son interprétation comme filehandle et non comme opérateur (voir perldoc -f print).
    Donc dans ton cas écrire :
    Sur le fond, cela évite l'usage des barewords, ce qui me semble une très bonne chose (http://fr.perlmaven.com/barewords-en-perl).
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  8. #8
    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 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par vince2005 Voir le message
    Enfin sur le fond, ça ne change absolument rien !
    Si, ça change pas mal de choses. Un file handle lexical, peut être transmis en paramètre comme une variable ordinaire à une fonction ou renvoyé en valeur de retour d'une fonction, ou même être rendu persistant dans une fermeture. On peut même stocker une série de file handles dans un tableau ou dans un hash. La portée lexicale d'un tel file handle permet d'éviter l'effet variable globale des barewords. Et le fichier ouvert se ferme automatiquement quand on sort de la portée lexicale du file handle. C'est déjà pas mal comme avantages, non?

    Sur la syntaxe à trois arguments, cela permet de séparer le nom du fichier du mode d'ouverture, c'est plus lisible, et c'est très utile quand on doit ouvrir un nom de fichier comportant des caractères spéciaux. Sous certains systèmes d'exploitations, le nom de fichier peut comporter des caractères spéciaux, y compris des espaces, certains signes de ponctuation ou les signes "<" et ">". Dans ce cas, l'ancienne syntaxe devient un casse-tête.

    Tous les ouvrages récents recommandent cette syntaxe, ce n'est pas pour rien.

  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 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Philou67430 Voir le message
    Attention cependant, pour éviter les ambiguité liées à la syntaxe de print, il faut, lorsque le filehandle n'est pas une bareword, le spécifier entre accolade (ou précédé du signe + pour forcer son interprétation comme filehandle et non comme opérateur (voir perldoc -f print).
    Donc dans ton cas écrire :
    Ce n'est pas du tout nécessaire dans un tel cas:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    print $OUT $ligne, "\n";
    marche très bien et ne pose aucun problème.

    C'est en revanche nécessaire si le filehandle est contenu dans un tableau ou dans un hachage:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    print {$tableau_de_fh[3]} "$ligne\n";
    print {$hachage_de_fh{fic_erreur}} "$ligne_en_erreur\n"

  10. #10
    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 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par JeanMi3000 Voir le message
    ça me fout 'les boules' car j'ai appris à coder en perl grâce à ce site
    Le tutoriel de Sylvain L. est vraiment très bien fait, mais il a un seul petit défaut: il date un peu et certaines choses ont été améliorées depuis.

    Deux choses au moins à changer:
    - utiliser "use warnings;" au lieu de "-w";
    - Ce que j'ai dit plus haut sur l'ouverture des fichiers.

  11. #11
    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 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par vince2005 Voir le message
    Enfin sur le fond, ça ne change absolument rien !
    Ça change tout.

    Pour donner un exemple de ce que je répondais déjà à ce message plus haut, je me suis amusé à rédiger un petit programme qui lit en entrée une liste des 5064 mots différents du Code civil français (tel que téléchargé il y a environ un an) avec leur fréquence d'apparition, trié par cette fréquence d'apparition puis par ordre alphabétique, et à créer 26 fichiers différents, un par lettre initiale des mots en question.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    use strict;
    use warnings;
     
    my %dispatch;
    $dispatch{$_} = create_sub($_) for ('a'..'z');
    while (<>) {
    	$dispatch{$1}->($_) if (/^([a-z])/) ;
    }
    sub create_sub {
    	my $letter = shift;
    	my $file_name = "lettre_$letter.txt";
    	open my $FH, ">", $file_name or die "ouverture impossible de $file_name $!";
    	return sub { my $line = shift; print $FH $line; }
    }
    Vingt-six fichiers à créer, vingt-six filehandles, et tout le reste, et le programme tient en 15 lignes de code, dont moins de 10 de code exécutable réel!
    Voici un extrait du fichier en entrée (tous les mots du Code civil français (normalisés, sans accent ni majuscule) avec leur fréquence d'apparition):
    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    de 7397
    l 4295
    ou 3976
    a 3538
    d 3499
    la 3127
    article 2204
    des 1999
    une 1937
    les 1912
    le 1832
    par 1665
    est 1614
    un 1589
    et 1542
    en 1075
    ans 928
    du 913
    dans 774
    pour 770
    au 755
    amende 730
    emprisonnement 652
    prevues 614
    personne 593
    euros 533
    peines 521
    aux 512
    fait 503
    puni 490
    qui 486
    sont 477
    infraction 462
    ...
    visite 1
    visuels 1
    vivants 1
    voiture 1
    vole 1
    voyage 1
    zone 1

    Voici une liste des 26 fichiers créés:
    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
    25
    26
    -rw-r--r--  1 Laurent None           0 18 nov.  23:23 lettre_x.txt
    -rw-r--r--  1 Laurent None        1129 18 nov.  23:23 lettre_o.txt
    -rw-r--r--  1 Laurent None          15 18 nov.  23:23 lettre_z.txt
    -rw-r--r--  1 Laurent None         288 18 nov.  23:23 lettre_q.txt
    -rw-r--r--  1 Laurent None         504 18 nov.  23:23 lettre_b.txt
    -rw-r--r--  1 Laurent None        5149 18 nov.  23:23 lettre_c.txt
    -rw-r--r--  1 Laurent None        4883 18 nov.  23:23 lettre_p.txt
    -rw-r--r--  1 Laurent None         977 18 nov.  23:23 lettre_l.txt
    -rw-r--r--  1 Laurent None        3000 18 nov.  23:23 lettre_s.txt
    -rw-r--r--  1 Laurent None         840 18 nov.  23:23 lettre_v.txt
    -rw-r--r--  1 Laurent None         722 18 nov.  23:23 lettre_n.txt
    -rw-r--r--  1 Laurent None        2076 18 nov.  23:23 lettre_m.txt
    -rw-r--r--  1 Laurent None        4025 18 nov.  23:23 lettre_e.txt
    -rw-r--r--  1 Laurent None        1559 18 nov.  23:23 lettre_t.txt
    -rw-r--r--  1 Laurent None        3385 18 nov.  23:23 lettre_i.txt
    -rw-r--r--  1 Laurent None         542 18 nov.  23:23 lettre_g.txt
    -rw-r--r--  1 Laurent None        1574 18 nov.  23:23 lettre_f.txt
    -rw-r--r--  1 Laurent None           5 18 nov.  23:23 lettre_y.txt
    -rw-r--r--  1 Laurent None         321 18 nov.  23:23 lettre_u.txt
    -rw-r--r--  1 Laurent None           6 18 nov.  23:23 lettre_k.txt
    -rw-r--r--  1 Laurent None         638 18 nov.  23:23 lettre_h.txt
    -rw-r--r--  1 Laurent None         428 18 nov.  23:23 lettre_j.txt
    -rw-r--r--  1 Laurent None        3396 18 nov.  23:23 lettre_r.txt
    -rw-r--r--  1 Laurent None        3951 18 nov.  23:23 lettre_d.txt
    -rw-r--r--  1 Laurent None          19 18 nov.  23:23 lettre_w.txt
    -rw-r--r--  1 Laurent None        4602 18 nov.  23:23 lettre_a.txt
    Et, à titre d'exemple, le fichier pour la lettre "g":
    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     
    $ cat lettre_g.txt
    general 47
    gerer 32
    grossesse 32
    genetiques 29
    guerre 28
    groupement 23
    groupe 18
    grace 16
    gametes 15
    gravite 13
    groupes 13
    gendarmerie 12
    gravement 9
    garanties 8
    guet-apens 8
    garde 7
    gardien 7
    gardiennage 7
    generales 7
    geneve 6
    grave 6
    graves 5
    groupements 5
    genetique 4
    genocide 4
    greffe 4
    gage 3
    genetiquement 3
    global 3
    greffes 3
    garantie 2
    generale 2
    gerant 2
    germinaux 2
    gestes 2
    gouvernement 2
    gre 2
    gallodrome 1
    garantir 1
    garantit 1
    gaz 1
    generalisee 1
    generaux 1
    generosite 1
    gens 1
    gracieuse 1
    grande 1
    grandes 1
    gratuit 1
    grevee 1
    Tu sais faire cela en 15 lignes de code avec des filehandle de type bareword et l'ancienne syntaxe pour open?

    A ta disposition, bien sûr, pour expliquer comment ça marche.

  12. #12
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Citation Envoyé par Lolo78 Voir le message
    Ce n'est pas du tout nécessaire dans un tel cas:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    print $OUT $ligne, "\n";
    marche très bien et ne pose aucun problème.
    Ça n'est pas "toujours" nécessaire, mais ça me semble toujours "utile" : ça permet d'avoir une syntaxe "uniforme", et de ne jamais se poser la question.
    Et si la liste des paramètres du print change, ça reste toujours valide.
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 124
    Points : 94
    Points
    94
    Par défaut
    Citation Envoyé par Lolo78 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    while (<>) {
    	$dispatch{$1}->($_) if (/^([a-z])/) ;
    }
    Salut.
    n'étant pas un vieux perliste, je ne comprend pas le $1 de $dispatch{$1}, si il y avait un lien qui donne des explications là dessus.
    Ensuite un commentaire sur le code. Le mot étoile par exemple n'est pas trouvé. Perso j'utilise et sur-utilise la fonction exist, et je serais certainement passé par là pour écrire une fonction semblable qui m'aurais permis de trouver le é de étoile.
    j'espère ne pas être trop hors sujet.

  14. #14
    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 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Le $1 est la première lettre du mot examiné, capturée par l'expression régulière /^([a-z])/.

    Sinon, ma liste en entrée est une liste de tous les mots du Code civil, sans accents et sans majuscules, avec leur fréquence d'apparition dans le code civil (un seul mot par ligne). Il ne peut donc y avoir "étoile", seulement éventuellement "etoile". C'est pourquoi l'expression régulière utilisée (classe de caractères [a-z]) ne recherche que les 26 lettres de base.

    Je n'ai pas besoin de la fonction exists, puisque je me contente de lire la liste de mots en entrée (sans accents, ni cédilles, etc.) et de répartir les mots entre 26 fichiers, selon la première lettre du mot. Si ma liste en entrée avait eu des accents, des cédilles ou des lettres capitales, il aurait fallu que j'ajoute des expressions régulières pour tenir compte compte de ces différents cas particuliers.

    Si tu as testé avec une liste contenant des lettres accentuées ou des lettres capitales, ça ne marche pas, il faut ajuster le programme.

  15. #15
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 124
    Points : 94
    Points
    94
    Par défaut
    ok.
    donc si j'ai bien compris tu transforme le résultat d'une expression régulière en fonction, que tu appliques à l'entrée que fournit la boucle.
    En quelque sorte tu marches à l'envers. C'est malin mais c'est une gymnastique pour celui qui n'en à pas l'habitude.

  16. #16
    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 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    La ligne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $dispatch{$_} = create_sub($_) for ('a'..'z');
    crée ce que l'on appelle une table de distribution (dispatch table), c'est-à-dire un hachage dans lequel les clefs sont les 26 lettres de l'alphabet et les valeurs 26 fonctions anonymes écrivant chacune dans son propre fichier.

    Ensuite, en récupérant la première lettre du mot, j'utilise le hash %dispatch pour lancer la fonction correspondante.

    Bonne fin de journée

  17. #17
    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 469
    Points
    12 469
    Billets dans le blog
    1
    Par défaut
    Bon, j'avoue, je me suis un peu fait plaisir ci-dessus, en utilisant des fermetures anonymes. Le code que j'ai présenté ci-dessus dérive de la solution que j'avais trouvée à un cas réel dans lequel je devais écrire dans environ 350 fichiers différents. Il était hors de question, dans mon esprit, d'écrire 350 fois un truc du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    my $file1 = "file1.txt";
    open my FIC1, ">", file1.txt or die ...
    my $file2 = ...
    ...
    my $file350 = ...
    et puis, plus loin:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    if ($value == 1) {
         print $FIC1 $outline;
    } elsif ($value = 2) {
         print $FIC2 ...
    ...
    } elsif ($value == 350) {
         print ...
    }
    Cela m'aurait obligé à écrire environ 1500 lignes de code répétitif rien que pour la gestion des fichiers et des files handles, non merci.

    J'ai donc adopté la stratégie du code présenté dans mon précédent post, où toute la partie gestion des fichiers et file handles tenait en une grosse dizaine de lignes de code. Même si j'ai un peu galéré cette première fois et mis trois ou quatre heures à mettre au point, je restais largement gagnant par rapport à 1500 lignes de codes forcément sujettes à de nombreuses erreurs de copier-coller. Et un code de 10 lignes est bien plus maintenable qu'un code de 1500 lignes. Mais je reconnais que la méthode employée est assez subtile et peut être difficile à comprendre pour un débutant.

    Dans le cas très simple de la répartition des mots selon la lettre initiale de mon post ci-dessus, il y a un autre moyen, ni plus ni moins long, mais sans doute un peu plus facile à saisir. Il s'agit de créer un hachage de file handles:
    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
     
    use strict;
    use warnings;
     
    my %handles;
    $handles{$_} = create_fh($_) for ('a'..'z');
    while (<>) {
    	print { $handles{$1} } $_ if (/^([a-z])/) ;
    }
     
    sub create_fh {
    	my $letter = shift;
    	my $file_name = "lettre_$letter.txt";
    	open my $FH, ">", $file_name or die "ouverture impossible de $file_name $!";
    	return $FH;
    }
    Le code est très proche et est basé sur la même idée générale, sauf que la fonction auxiliaire (create_fh) appelée 26 fois renvoie cette fois des filehandles qui sont ensuite stockés dans le hachage %handles.

    Mais dans le cas fonctionnellement plus complexe de mes 350 fichiers, il y avait un vrai avantage à utiliser une table de distribution de fonctions anonymes plutôt qu'un hachage de filehandles. Ces fonctions anonymes, qui agissent comme des fermetures, permettaient de stocker dans l'environnement d'exécution de chaque fonction non seulement le filehandle, mais aussi d'autres données spécifiques à chacune d'elles. Avec la méthode ci-dessus, j'aurais eu besoin de maintenir une structure de données nettement plus complexe (plusieurs hachages ou hachages de hachages).

    Bref, pour le cas simple des 26 lettres, les deux méthodes se valent (même nombre de lignes de code) et la seconde immédiatement ci-dessus est sans doute plus simple à comprendre, mais, dans un cas plus général, la méthode de la table de distribution (hachage de fermetures anonymes) s'avère nettement plus puissante.

    Cela dit, dans les deux cas, cela n'est possible que grâce à l'existence des filehandles lexicaux, dont on peu contrôler la portée, que l'on peut passer à une fonction ou renvoyer à la fonction appelante, que l'on peut stocker dans un tableau ou un hachage, etc. Rien de tout cela n'est possible avec les filehandles de type "bareword".

    Perl est intrinsèquement largement plus expressif et concis que, par exemple, C, C++ ou Java, même si on code en Perl comme si c'était du C. On peut couramment faire la même chose avec des programmes 5 à 10 fois plus courts (et 5 à 10 fois plus rapides à écrire). Mais si on commence à coder autrement en tirant parti des fonctionnalités relativement avancées de Perl, notamment celles issues de la programmation fonctionnelle, alors le gain n'est plus de 5 à 10, mais de 50 à 100, voire nettement plus dans certains cas. Pour mon cas des 350 fichiers, il m'aurait fallu environ 1500 lignes en écrivant du code "à la C". En C, il m'aurait sans doute fallu 7000 à 10000 lignes de code, donc le gain était indéniablement significatif. Mais avec la méthode que j'ai employée, résultant en environ 10 lignes de code pour la gestion des fichiers et des filhandles, le facteur de gain par rapport à C est compris entre 700 ou 1000. Je pense qu'avec cela, tu comprendras pourquoi je suis pour ainsi dire amoureux du langage Perl. J'ai vraiment réussi, encore la semaine dernière, à faire en moins de 20 minutes des choses sur lesquelles des collègues galéraient depuis plusieurs jours.

    Cela dit, je ne critique pas pour autant les gens qui n'exploitent pas ces possibilités relativement avancées de Perl. Ne serait-ce que parce que j'ai été moi-même dans ce cas pendant les 5 ou 6 premières années où j'ai utilisé ce langage (à titre d'excuse, je dirais que je ne l'utilisais à l'époque que de façon relativement épisodique, peut-être un total de 20 ou 30 jours par an).

    Ayant été amené à l'utiliser de façon beaucoup plus intensive ces 5 ou 6 dernières années, j'ai progressivement investi dans l'utilisation de concepts plus avancés, et, vraiment, je ne regrette pas. Comme consultant expert indépendant capable de faire parfois des miracles inattendus, je gagne presque 50% de plus que mon chef et je gagne même plus que le chef de mon chef (bon, ce n'est pas seulement ma connaissance de Perl qui me donne cette position, c'est aussi une excellente connaissance fonctionnelle acquise sur 16 ans de l'application principale du client). Et je m'éclate à coder, parce que c'est ce que j'aime faire, au lieu de me faire ch*... comme eux à gérer des budgets ou faire du reporting de m*.

  18. #18
    Membre chevronné Avatar de dmganges
    Homme Profil pro
    Retraité. Ne recherche pas un emploi.
    Inscrit en
    Septembre 2011
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 71
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Retraité. Ne recherche pas un emploi.
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2011
    Messages : 1 392
    Points : 2 044
    Points
    2 044
    Par défaut
    Dommage qu'on ne puisse pas faire +2 à Lolo78

  19. #19
    Expert confirmé

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2009
    Messages
    3 577
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 58
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Avril 2009
    Messages : 3 577
    Points : 5 753
    Points
    5 753
    Par défaut
    Un algorithme intermédiaire entre les 1500 lignes de code où chaque handle de fichier est stocké dans une variable séparée, et un tableau dispatcher de fermetures anonymes est le tableau de handle de fichier, qui nécessite lui aussi un nombre limité de ligne de code pour ouvrir et écrire dans le fichier adhoc, et une factorisation des appels d'ouverture et d'écriture dans ces fichiers (que ce soit en perl, en C/C++ ou Java)

    Cela dit, la solution des fermetures est élégante et efficace (elle ne nécessite pas de se soucier du stockage des handle et limite l'usage de variables globales
    Plus j'apprends, et plus je mesure mon ignorance (philou67430)
    Toute technologie suffisamment avancée est indiscernable d'un script Perl (Llama book)
    Partagez vos problèmes pour que l'on partage ensemble nos solutions : je ne réponds pas aux questions techniques par message privé
    Si c'est utile, say

  20. #20
    Membre régulier
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    124
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 124
    Points : 94
    Points
    94
    Par défaut
    Citation Envoyé par Lolo78 Voir le message
    Bon, j'avoue, je me suis un peu fait plaisir ci-dessus, en utilisant des fermetures anonymes.
    Salut
    j'apprécie toujours les codes que tu publie mais il se trouve que justement j'étais entrain de réfléchir à une problématique de ce type et ton post tombait pile poil. J'ai donc adapté à mes besoins ce que tu as écrit.
    voilà ce qu ça donne.
    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
    open( my $in, $adresse )  or die "Pas moyen d'ouvrir $adresse: $!";
    my %dispatch;
    while (<$in>) {
     
            if($_ =~ /cequejecherche.+?cequejetrouve(.+?)\]/){
                    my $result = $1;
                    $result =~ s/ /_/g;
                    if ( ! exists ( $dispatch{$result})) {
                            $dispatch{$result} = create_sub($result);
                            $dispatch{$result}->($_);
                    }else{
                    $dispatch{$result}->($_);
            }
    }
     
    }
    sub create_sub {
    my $letter = shift;
    my $file_name = "depot/$letter.txt";
    open my $FH, ">>", $file_name or die "ouverture impossible de $file_name $!";
    return sub { my $line = shift; print $FH $line; }
                                    }
                                    exit 0
    j'ai employé exists par ce que je ne connais pas ce que je cherche
    et j'ai remis le if à l'endroit car définitivement je n'arrives pas à encadrer le " je fais ceci " if quelquechose
    Cela dit je pense que l'esprit général est sauvgardé et le tout fonctionne parfaitement.
    Bonne journée et merci

Discussions similaires

  1. Supprimer les doublons dans un fichier
    Par ninou blue dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 18/12/2014, 21h52
  2. [XL-2007] Trier fichiers excel pour supprimer les doublons
    Par El-Cherubin dans le forum Excel
    Réponses: 3
    Dernier message: 26/06/2009, 16h59
  3. Réponses: 1
    Dernier message: 02/07/2008, 19h49
  4. Renommer des fichiers en supprimant les doublons
    Par Serge63 dans le forum VBScript
    Réponses: 5
    Dernier message: 07/03/2008, 11h36
  5. Réponses: 2
    Dernier message: 21/02/2008, 13h29

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