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 :

Regroupement de lignes dans un fichier


Sujet :

Langage Perl

  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 10
    Points : 4
    Points
    4
    Par défaut Regroupement de lignes dans un fichier
    Bonjour,

    Je viens de débuter en PERL (merci d'avance dêtre indulgent).

    Je suis confronté à un problème qui m'agace depuis près d'une semaine maintenant.

    J'essaie de faire un script en PERL qui analyse un fichier de log Apache.

    Jusqu'ici pas de problème, je récupère les temps HTTP de chaque requête : que du bonheur.

    Jusqu'a ce que je décide d'optimiser mon script de manièere à ce qu'il me regroupe chaque reqêtes en fonction d'un clic.

    Et la cela devient problématique: le nombre de requete pour chaque clic dépend du nombre de beaucoup de facteur : première connexion ou pas, .....

    J'essiae de faire cela que pour la connexion et la deconnexion pour le moment alors j'ai identifié les requete pour ces deux clics.

    Mais je ne sais pas du tout comment m'y prendre pour mettre tout cela en forme, le nouveau script doit partir du fichier résultat de mon premier script (qui a deja épuré les logs).

    Le fichier d'entré est de la forme:

    req1 10
    req2 15
    req3 20
    req8 54564
    req3 21312
    req7 2425
    req9 4545
    req0 5
    req6 10

    il faut savoir que l'enchainement req1 req2 req3 correspond à la connexion
    et que l'enchainement req0 req6 correspond à la deconnexion

    le but etant de faire la somme de ces requete et de les remplacé par le nom du clic, le résultats voulu:

    connexion 45
    req8 54564
    req3 21312
    req7 2425
    req9 4545
    deconnexion 15

    Voici le code que j'ai entreprit:
    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
    undef $/;
    $nom_fic = $ARGV[0];
    $traitement = $ARGV[1];
    $debut=time;
    $tps=0;
    open(FILE,$nom_fic);
      # On décompose l'enregistrement
    	while (<FILE>) 
    	{
     		undef %attr_value;
     
    		($tps1,$tps2) = split /=/,$_,2;
     
     
     
     
    		if($tps1 eq "req1")
    		{
    			$tps=$tps2+$tps;
    			print "temps ",$tps,"\n";
    			if($tps1 eq "req2")
    		 	{
    		 		$tps=$tps2+$tps;
    				print "temps ",$tps,"\n";
    		 		print "conn ",$tps,"\n";
    		 	}
    		}
     
    	$tps=0;
     
      }
     
    close(FILE);

    Mais je n'arrive pas à faire des if sur plusieurs lignes.....


    please help me

    Merci d'avance!

  2. #2
    Membre émérite
    Avatar de Jasmine80
    Femme Profil pro
    Bioinformaticienne
    Inscrit en
    Octobre 2006
    Messages
    3 157
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 44
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Bioinformaticienne
    Secteur : Santé

    Informations forums :
    Inscription : Octobre 2006
    Messages : 3 157
    Points : 2 673
    Points
    2 673
    Par défaut
    Peut-être un code dans ce genre :

    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
     
    #!/usr/bin/env perl
     
    use strict;
    use warnings;
     
     
    # définition des numéros de req de la connexion
    my @connection;
    $connection[1] = 1;
    $connection[2] = 1;
    $connection[3] = 1;
     
    # définition des numéros de req de la déconnexion
    my @deconnection;
    $deconnection[0] = 1;
    $deconnection[6] = 1;
     
    # sommes des connexions et déconnexions
    my $connec_sum;
    my $decon_sum;
     
     
    open my $data, '<', 'data.txt' or die $!;
    open my $outfile, '>', 'output.txt' or die $!;
     
    while (my $line = <$data>){
     
    	if ($line =~ m/req(\d+)\s+(\d+)$/){
     
    		my $req = $1;
    		my $val = $2;
     
    		if ( (defined $connection[$req]) && ($connection[$req] == 1) ) {
    			$connec_sum += $val;
    			$connection[$req] = 0;
    		}
    		elsif (defined $deconnection[$req]){
    			$decon_sum += $val;
    		}
    		else {		
    			print $outfile $line;
    		}
    	}
    }
     
    print $outfile "connexion $connec_sum\n";
    print $outfile "deconnexion $decon_sum\n";
     
    close $data;
    close $outfile;
    -- Jasmine --

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 10
    Points : 4
    Points
    4
    Par défaut
    Merci pour la proposition de code!
    l'idée de copier le fichier dans un tableau est excellente, cependant, une requete peut etre utilisé dans plusieyurs clic:
    connexion correspond à req1 req2 et req3
    mais on a aussi la page d'acceuil qui correspond à req5 et req3

    le but serait de vérifier la suite logique des req (et donc des lignes )

    si on a
    123 => connexion
    si on a
    53=> acceuil
    si on a
    06= Deconnexion


    Merci de ton aide.

  4. #4
    Candidat au Club
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 10
    Points : 4
    Points
    4
    Par défaut
    Voici l'algorithme que j'essaie de mettre en pratique:

    Si (ligne == req1) et (ligne_suivante == req2) et (ligne_suivante_suivante ==req3)
    alors
    tps = val1+val2+val3
    affiche( "connexion ", tps)
    Si (ligne == req0) et (ligne_suivante == req6)
    alors
    tps = val0+val6
    affiche( "deconnexion ", tps)
    Si (ligne == req5) et (ligne_suivante == req3)
    alors
    tps = val5+val3
    affiche( "acceuil ", tps)
    Si (ligne == req5) et (ligne_suivante == req8) et (ligne_suivante == req9)
    alors
    tps = val5+val8+val9
    affiche( "recherche ", tps)


    et ainsi de suite jusqu'a simuler tout les clic possible du site.
    Merci de votre aide.

  5. #5
    Membre régulier Avatar de Olivier.p
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    89
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2009
    Messages : 89
    Points : 93
    Points
    93
    Par défaut
    Bonjour, je ne vois pas pourquoi tu n'arrives pas à écrire cet algorithme en perl...
    Qu'est ce que tu n'arrives pas à écrire exactement ?

  6. #6
    Candidat au Club
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 10
    Points : 4
    Points
    4
    Par défaut
    Je n'arrive pas à mettre en place une condition sur plusieurs ligne.

    lorsque je fait mon while(<FILE>), je parcoure le fichier ligne par ligne sans connaitre les valeurs des lignes suivantes et

    Je crois avoir eu un illumination en répondant:
    je n'ai qu'à mettre une variable dans la boucle qui prend en paramètre le numero de la requete et si cette variable est égal à 123 alors j'ecris connexion avec la somme des temps.
    et je remet la variable à zéro ....


    je vais essayer de mettre cela en pratique ...je vous tiens au courant.

    Si vous avez une meilleur idée je suis preneur ...

  7. #7
    Membre régulier Avatar de Olivier.p
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    89
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2009
    Messages : 89
    Points : 93
    Points
    93
    Par défaut
    Le module tie::file est ton ami

    Ce module permet d'enregistrer le contenu de ton fichier dans un tableau (une ligne par case) ce qui te permet de naviguer via dans les indices du tableau.

    De plus ce module gère aussi les gros fichiers en ne copiant pas tout le contenu en mémoire.

  8. #8
    Candidat au Club
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 10
    Points : 4
    Points
    4
    Par défaut
    je ne connais pas ce module (sa fait qu'une semaine que j'ai commencer le perl) mais je vais l'étudier!

    pour le moment voici le code réalisé:
    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
    #!/usr/bin/perl
     
    #undef $/;
    $nom_fic = $ARGV[0];
    $traitement = $ARGV[1];
    $debut=time;
    $tps=0;
    	$req = 0;
    		$val = 0;
    		$connec_sum = 0;
    open(FILE,$nom_fic);
      # On décompose l'enregistrement
    	while (<FILE>) 
    	{
    	 		undef %attr_value;
    		($tps1,$tps2) = split /=/,$_,2;
     
    		$req = $req.$tps1;
    		$val = $val+$tps2;
     
    		$ligne = $ligne+1;
    	if( $req eq "0Req1Req2Req3")
    	{	print "connexion ", $val,"\n";
    		$req = 0;
    	}
     
     
      }
     
     
    close(FILE);
    Et sa à l'air de fonctionner (pour le connexion pour le moment).

    Qu'en penser vous?

  9. #9
    Membre régulier Avatar de Olivier.p
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    89
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2009
    Messages : 89
    Points : 93
    Points
    93
    Par défaut
    De débutant à débutant je dirais qu'à part si ta séquence commence par

    0
    Req1
    Req2
    Req3

    ça ne marche pas.

    Si il y a une autre requête avant il va toujours tout mettre à la suite. Je m'explique : avec la requête suivante :

    Req4 (au hasard)
    Req7 (au hasard aussi)
    0
    Req1
    Req2
    Req3
    Req8 (au hasard)

    Ton script va tester
    Req4 -> faux donc ne fait rien
    Req4Req7 -> faux donc ne fait rien
    Req4Req70 -> faux donc ne fait rien
    Req4Req70Req1 -> faux donc ne fait rien
    Req4Req70Req1Req2 -> faux donc ne fait rien
    Req4Req70Req1Req2Req3 -> faux donc ne fait rien
    Req4Req70Req1Req2Req3Req8 -> faux donc ne fait rien

    Fin de fichier.

    Ton avis ?

  10. #10
    Candidat au Club
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 10
    Points : 4
    Points
    4
    Par défaut
    débutant mais avec une sacrée logique

    je me suis rendu compte du problème :
    j'ai modifié le fichier de manière à catcher toute les requêtes: dans mon premier fichier j'ai épuré les requête de manière à n'avoir que les requêtes qui sont déclaré comme étnt des suite logique: la connexion et la deconnexion et maintenant je fais la même chose pour la recherche (en tout je dois capturer une dizaine d'actions utilisateurs)

    je n'ai pas trouvé de solution plus propre ...c'est un script fait avec un rouleau de scotch ..j'espere que sa tiendra le temps que je monte en compétence en perl pour optimiser le bébé ...

  11. #11
    Membre régulier Avatar de Olivier.p
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    89
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2009
    Messages : 89
    Points : 93
    Points
    93
    Par défaut
    Bonne chance à toi ! Tiens nous au courant

  12. #12
    Candidat au Club
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 10
    Points : 4
    Points
    4
    Par défaut
    Citation Envoyé par Olivier.p Voir le message
    Bonne chance à toi ! Tiens nous au courant
    Je vais essayer d'améliorer le truc ....en attendant je laisse le thread ouvert ...pour moi ce n'estpas encore résolu (ma technique en carton c'est pas top ... )

  13. #13
    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
    Bonjour,

    Ta problématique me fait penser à un automate d'état fini.
    Il y a bien des modules CPAN pour cela (j'en ai repéré au moins 2 : DFA::Simple et DMA::FSM) mais j'avoue ne pas m'y être attardé.

    Comme le sujet m'intéresse, j'ai donc créer ce petit prototype de traitement d'un FSM (Finite State Machine) dont il faudrait naturellement "modulariser" (voire "objectiser") la partie générique.

    Ce script traite correctement la cas suivant :
    req1 10
    req2 15
    req3 20
    req8 54564
    req3 21312
    req7 2425
    req9 4545
    req0 5
    req6 10
    en donnant ce résultat.
    $ cat log.txt | ./fsm.pl 2>/dev/null
    connexion 45
    req8 54564
    req3 21312
    req7 2425
    req9 4545
    deconnexion 15
    Naturellement, je ne l'ai pas testé pour les autres cas, il peut donc contenir des bugs, mais ça devrait rester une bonne base de travail.
    Le script :
    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
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    #!/usr/bin/perl
     
    use strict;
    use warnings;
    use Carp;
    use List::Util qw(sum);
     
    {
      my $fsm_state;
      # Méthode d'initialisation de la machine d'état (définition du premier état)
      sub fsm_start {
        my $fsm = shift;
        $fsm_state = shift;
     
        croak "Un hashage de définition de machine d'état doit être fourni\n" if !%$fsm;
        croak "Un état de démarrage doit être spécifié parmi les suivants".(join ", ", keys %$fsm)."\n"
          if !defined $fsm_state || !exists $fsm->{$fsm_state};
      }
     
      # Méthode d'exécution de la machine d'état (calcule l'état suivant selon l'état courant)
      sub fsm {
        my $fsm = shift;
        croak "fsm_start doit être appelé avec un état initial valide avant d'exécuter cette fonction\n"
          if !defined $fsm_state;
     
        confess "Erreur pannique, l'état courant [$fsm_state] n'existe pas dans la machine d'état"
          if !exists $fsm->{$fsm_state};
     
        # changer d'état, sauf si l'état est indéfini ou vide
        my $next_state = $fsm->{$fsm_state}->() || $fsm_state;
        warn "$fsm_state => $next_state\n";
     
        croak "Le nouvel état proposé depuis l'état [$fsm_state] n'existe pas dans la machine d'état ([".($next_state || "aucun")."])\n"
          if !exists $fsm->{$next_state};
        $fsm_state = $next_state;
      }
    }
     
    my @req = ();
    my ($req, $val);
     
    # Fonction d'affichage des requètes
    sub affiche {
      my ($request) = @_;
     
      print join(" ", @{$_}), "\n" foreach @$request;
      @$request = ();
    }
     
    # Fonction de calcul du cumul de temps des requètes
    sub tps {
      my ($request) = @_;
     
      # retourner la somme des valeurs (2e élément de chaque requete)
      my $tps = sum(map $_->[1], @$request);
      @$request = ();
     
      return $tps;
    }
     
    # Définition de état de la machine d'état (chaque valeur est une fermeture qui retourne le nouvel état)
    my %fsm = ( "init" => sub {
                  my $next_state;
                  if ($req eq "req1") {
                    $next_state = "conn_1";
                  }
                  elsif ($req eq "req0") {
                    $next_state = "deco_1";
                  }
                  elsif ($req eq "req5") {
                    $next_state = "other_1";
                  }
                  else {
                    affiche(\@req);
                  }
                  $next_state;
                },
                "conn_1" => sub {
                  my $next_state;
                  if ($req eq "req2") {
                    $next_state = "conn_2";
                  }
                  else {
                    affiche(\@req);
                  }
                  $next_state;
                },
                "conn_2" => sub {
                  if ($req eq "req3") {
                    # On remplace les requètes par une requète connexion
                    @req = ([ "connexion ", tps(\@req) ]);
                  }
                  affiche(\@req);
                  "init";
                },
                "deco_1" => sub {
                  if ($req eq "req6") {
                    # On remplace les requètes par une requète deconnexion
                    @req = ([ "deconnexion ", tps(\@req) ]);
                  }
                  affiche(\@req);
                  "init";
                },
                "other_1" => sub {
                  my $next_state = "init";
                  if ($req eq "req8") {
                    $next_state = "rech";
                  }
                  else {
                    if ($req eq "req3") {
                      # On remplace les requètes par une requète accueil
                      @req = ([ "accueil", tps(\@req) ]);
                    }
                    affiche(\@req);
                  }
                  $next_state;
                },
                "rech" => sub {
                  if ($req eq "req9") {
                    # On remplace les requètes par une requète recherche
                    @req = ([ "recherche ", tps(\@req) ]);
                  }
                  affiche(\@req);
                  "init";
                },
           );
     
    fsm_start(\%fsm, "init");
    while (<STDIN>) {
      ($req, $val) = split /\s+/;
      push @req, [ $req, $val ];
      fsm(\%fsm);
    }
    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

Discussions similaires

  1. [FSO] Effacer une ligne dans un fichier
    Par Johnbob dans le forum ASP
    Réponses: 4
    Dernier message: 30/05/2007, 16h23
  2. retoure à la ligne dans un fichier
    Par adilou1981 dans le forum Langage
    Réponses: 4
    Dernier message: 02/12/2004, 15h05
  3. [Fichier] Nombre de ligne dans un fichier texte
    Par NewSer dans le forum Entrée/Sortie
    Réponses: 7
    Dernier message: 10/11/2004, 16h58
  4. Réponses: 2
    Dernier message: 02/03/2004, 19h38
  5. Supprimer une ligne dans un fichier
    Par sbeu dans le forum Langage
    Réponses: 3
    Dernier message: 13/05/2003, 10h30

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