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

 C Discussion :

Faire un programme qui fait l'équivalent de "grep"


Sujet :

C

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2021
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2021
    Messages : 2
    Par défaut Faire un programme qui fait l'équivalent de "grep"
    Bonjour,

    J'ai commencé la programmation il y a deux mois et j'ai un projet à réaliser. Je suis perdu parce que je ne dispose pas de cours à l'heure actuelle et je viens donc faire appel à votre savoir-faire pour m'aiguiller un peu svp. (Après des heures à essayer j'ai bien compris que j'y arriverai pas tout seul)

    Je dois écrire un programme qui compte le nombre de lignes d'un fichier de logs (ça j'ai réussi) mais je dois aussi les compter par mois. Je m'explique. Le format des logs fait que après l'IP, il y a un champ qui correspond à la date genre [21/Feb...].
    Il faudrait donc que mon programme renvoie quelque chose du genre :

    Jan : 300 connexions
    Feb : 200 connexions ...

    Pour le moment j'ai trouvé un programme qui a l'air bien, le voici :

    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
    134
    135
    136
    137
    138
    139
    140
    141
    142
    #include <stdio.h>
    #include <chaîne.h>
    #include <stdlib.h>
     
    /****************** Définition d'une structure ********************/
    typedef struct compteMot
    {
      caractère * mot;
      int nbOcc;
    }CompteMot;
     
    /************************ Les constantes ************************/
    enum {MAXLONGUEUR = 200} ;
     
    /* Le tableau où seront rangées les structures de type CompteMot */
    CompteMot *tableau;
     
    /* Le nombre de mots*/
    entier nbMots = 0 ;
     
    /* La taille du tableau contenant les mots */
    int tailleTableau = 50;
     
    char chercherIndice(char *, int *);
    char placer(char *, int);
     
    /************************ La fonction principale *******************
     Le programme : 
     - Ouvre en lecture un fichier contenant un texte, fichier dont le nom 
     est indiqué sur la ligne de commande. Dans le cas où l'utilisateur omet
     de donner un nom de fichier d'entrée sur la ligne de commande, le programme 
     demande à l'utilisateur d'indiquer le texte directement par le clavier. 
     - Trie les mots et compte le nombre d'occurrence de chaque mot 
     - Indique la liste triée des mots, un mot par ligne, avec pour chaque mot, 
     son nombre d'occurrences. Si l'utilisateur a donné sur la ligne de commande
     deux noms de fichiers, le premier pour le fichier d'entrée 
     contenant le texte, le second pour un fichier de sortie, cette liste est 
     sauvée sur le fichier de sortie. Sinon, la liste est indiquée à l'écran. */
    int main(int argc, char **argv)
    {
      char ligne[MAXLONGUEUR], *s, *mot;
      indice entier ;
      FICHIER *fichier;
      int je;
     
      if (argc > 1) fichier = fopen(argv[1], "r");
      autre 
        {
          fichier = stdin;
          printf("Indiquez votre texte\n");
        }
      tableau = (CompteMot *) malloc(tailleTableau * sizeof(CompteMot));
      si (tableau == NULL) 
        {
          printf("problème d'allocation\n");
          sortie(1) ;
        }
      while (fgets(ligne, MAXLONGUEUR, fichier) != NULL)
        {
          s = ligne;
          while ((mot = strtok(s, " []{}\\\n{}()*/\"#.;:,\t'?!-<>&%+=")) != NULL) 
    	{
    	  if (!chercherIndice(mot, &indice)) placer(mot,indice);
    	  else tableau[indice].nbOcc++;
    	  s = NULL ;
    	}
        }
      fclose(fichier);
      printf("\n");
      pour (i = 0; i < nbMots; i++)
        printf("%s : %d fois\n", tableau[i].mot, tableau[i].nbOcc); 
      renvoie 0 ;
    }
     
     
    /****************** La fonction chercherIndice *******************/
    /*Si le mot ne figure pas :
         - la fonction indiquée, avec la variable adrIndice, l'indice ou 
         il convient que le mot se trouve
         - la fonction retourne 0
      Si la figure donnée :  
         - la fonction indiquée, avec la variable adrIndice, l'indice ou 
         le mot figure
         - la fonction retourne 1*/
    char chercherIndice(char *mot, int *adrIndice)
    {
      int gauche = 0, droite = nbMots - 1;
      int milieu;
      int comparer ;
     
      tandis que (gauche <= droite)
        {
          milieu = (gauche + droite) / 2;
          compare = strcmp(mot, tableau[milieu].mot);
          si (comparer < 0) droite = milieu - 1;
          sinon si (comparer > 0) gauche = milieu + 1;
          autre 
    	{
    	  *adrIndice = milieu;
    	  retour 1 ;
    	}
        }
      *adrIndice = gauche;
      renvoie 0 ;
    }
     
    /****************** La fonction placer ******************/
    /*Decale vers la gauche les mots qui se trouvent
      a des indices aux moins egaux a "indice" et met le mot "mot" 
      a l'indice "indice" dans le tableau.
      ATTENTION : il faut allouer de la mémoire pour y mettre le nouveau
      mot par une copie */
    char placer(char *mot, int indice)
    {
      int je;
      char *leMot; 
     
      leMot = (char *) malloc((strlen(mot) + 1)*sizeof(char));
      si (leMot == NULL) 
        {
          printf("problème d'allocation\n");
          sortie(1) ;
        }
      strcpy(leMot, mot); 
      if (nbMots == tailleTableau) 
        {    
          printf("Le tableau est plein, nous reallouons\n");
          tailleTableau += 50;
          tableau = (CompteMot *) realloc(tableau,
    				      tailleTableau * sizeof(CompteMot));
          si (tableau == NULL) 
    	{
    	  printf("problème d'allocation\n");
    	  sortie(1) ;
    	}
        }
      pour (i = nbMots; i > indice; i--) tableau[i] = tableau[i - 1] ;
      tableau[indice].mot = leMot;
      tableau[indice].nbOcc = 1 ;
      nbMots++ ;
      retour 1 ;
    }
    Mais je dois être obligé de préciser sur ma ligne de commande la direction vers le fichier log et je n'ai pas réussi à faire en sorte que la redirection fonctionne. Plus problématique encore, je suis obligé de faire grep "nom du mois" pour ne pas avoir l'affichage pour chaque mot... mais j'ai aucune idée de comment retranscrire la commande grep en C.

    Voilà si vous pouviez m'aider, ça serait super.

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 836
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

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

    Informations forums :
    Inscription : Février 2006
    Messages : 12 836
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Pasimple Voir le message
    Bonjour,
    Salut

    Citation Envoyé par Pasimple Voir le message
    Il faudrait donc que mon programme renvoie quelque chose du genre :

    Jan : 300 connexions
    Feb : 200 connexions ...
    Ok. Donc créer un tableau de 12 ints. Puis examiner chaque ligne. Si la ligne contient "Jan", incrémenter le tableau [0]. Si elle contient "Feb" incrémenter le tableau [1] etc. En fin de programme, afficher les 12 valeurs.

    Citation Envoyé par Pasimple Voir le message
    Pour le moment j'ai trouvé un programme qui a l'air bien, le voici :
    Bien qu'en informatique on conseille de ne pas réinventer la roue, ce conseil s'adresse aux programmeurs confirmés. A ceux qui ont un projet, projet destiné justement à faire ressortir leur savoir faire, c'est alors le contraire. Là il vaut mieux tout faire pour apprendre justement à le faire.
    En plus, quand on conseille de ne pas réinventer la roue, c'est par rapport à des techniques de base (exemple un tri, une moyenne, une factorielle), techniques déjà en librairies sous formes de fonctions directement appelables. Aller chercher un programme "qui a l'air" (traduction "qui fait certaines choses") implique de le reprendre pour lui rajouter ce qui manque. Et bien souvent, reprendre un programme pour rajouter des actions manquantes est souvent plus difficile qu'écrire un programme neuf. Surtout vis à vis de ce programme qui teste malloc() mais qui ne teste pas fopen(), qui sort via une mystérieuse fonction "sortie()" non codée, qui intervertit "type" et "variable" (exemple ligne 42 indice entier à moins que le token "indice" signifie "type de variable" mais dans ce cas la variable se nommerait "entier" sauf que dans le code on demande bien la valeur de "indice" !!!) et surtout qui utilise des instructions aussi exotiques que "sinon si" ou "autre" qui, même si elles sont aisément compréhensibles, n'en demeurent pas moins des instructions étrangères au langage C. Bref ce programme ne compile pas ce qui est un minimum quand on veut le faire tourner (alors en ce qui concerne "le faire évoluer"...)

    Citation Envoyé par Pasimple Voir le message
    Mais je dois être obligé de préciser sur ma ligne de commande la direction vers le fichier log et je n'ai pas réussi à faire en sorte que la redirection fonctionne.
    Une redirection c'est une action de l'OS, pas du C. Si par exemple ton programme affiche des trucs à l'écran (printf()) alors la redirection permet à l'utilisateur de renvoyer ces affichages vers un fichier. Bref c'est justement une facilité que l'utilisateur puisse choisir librement vers quoi diriger les affichages du programme sans avoir à modifier le programme.

    Citation Envoyé par Pasimple Voir le message
    Plus problématique encore, je suis obligé de faire grep "nom du mois" pour ne pas avoir l'affichage pour chaque mot... mais j'ai aucune idée de comment retranscrire la commande grep en C.
    Et voilà. Et ce n'est pas en cherchant des programmes "qui ont l'air de faire des choses" que tu apprendras. Un algorithme se fait d'abord à la main. Si tu avais une ligne contenant "[...] 21/Jan:arrêt machine", comment ferais-tu pour identifier que la chaine "Jan" se trouve (ou pas) dans la ligne ? Une boucle sur chaque caractère de la ligne et regarder si à partir de ce caractère et les trois suivants on trouve la suite 'J', 'a', 'n' et surtout ':' (ce qu'on nomme communément une "sentinelle" pour éviter les confusions avec des strings style "Jante" ou "Janus"). Et sinon continuer (un autre algo plus rapide sera de d'abord chercher le ':' puis regarder les trois caractères précédents).
    Une fois l'algo trouvé, on le traduit en C. Et ensuite (là c'est l'expérience qui entre en jeu) on arrive à trouver comment séparer les choses. Par exemple moi j'écrirais une fonction qui reçoit en paramètre la ligne et le mois et qui répond si le mois est ou n'est pas dans la ligne. Ainsi le test de la réussite se résumerait à tester la fonction. Et une fois qu'elle est bien réglée, ne reste qu'à l'utiliser en sachant qu'elle ne pose pas de souci.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2021
    Messages
    2
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 22
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Décembre 2021
    Messages : 2
    Par défaut
    Merci beaucoup pour ton message.
    Après avoir réalisé ce boulot je ferai plus de programmation en C jusqu'à la fin de mes études du coup je t'avoue que je partais plus dans l'idée de reprendre un programme trouvé sur internet "qui partait bien", mais si tout écrire par moi-même est plus simple alors je vais continuer à essayer.

    Donc si je résume ce que je devrais faire c'est :
    un tableau avec comme cases chaque mois et une augmentation de +1 pour chaque ligne du mois rencontrée pendant la lecture du fichier.
    Du coup j'ai juste un tableau de 13 cases en tout (\o à la fin je crois) et je fais des printf à la fin.
    J'ai aucune idée de comment je peux faire pour que le fichier soit analysé et que les chaînes de caractères des mois soient reconnus mais je vais essayer de trouver des ressources sur internet.

  4. #4
    Membre expérimenté

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    329
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 329
    Par défaut
    Oui c'est ça qui est "gai" en programmation, essayer de trouver une astuce pour apporter une solution à une difficulté particulière.
    Quand on a pas beaucoup d'expérience cela peut s'avérer fastidieux... quels sont les termes corrects à utiliser ?
    Ici, a priori, tu connais déjà la "fonction grep" et tu as trouvé un exemple dans lequel il y a de chouettes indices qui pourraient te permettre d'atteindre tes objectifs.

    De plus les conseils de Sve@r sont pertinents (évidemment)... tu devrais y arriver avec tout cela.

    Fais d'abord un plan: qu'est-ce que tu as "en entrée" ? Un fichier de log... OK
    Que dois-tu faire avec ce fichier de log ? Calculer le nombre de connexions pour les mois de l'année... ("en sortie", par exemple, une liste des mois et le nombre de connexions)

    Pour déterminer le mois de l'année qu'as-tu comme infos dans le fichier ? Une "sous chaîne de caractères" puis un caractère donné -> ':'...
    Comme le dit Sve@r: essaye de décomposer ton programme (ou l'idée de ton programme, comment tu voudrais que ton programme fonctionne) en tâches simples.

    Puis tu "simules" l'exécution de ton programme sur papier avec, par exemple, le fichier log sous les yeux... une fois que cela te semble tenir la route, il faudra pour chaque tâche simple
    essayer de trouver une fonction en C qui l'opère... et pour cela les exemples -- quand ils sont commentés et corrects -- peuvent t'aider.

    Pour isoler une sous-chaîne dans une chaîne de caractères (une ligne de ton fichier log) il existe des techniques et des fonctions différentes mais il y en a qui sont simples il faut juste un peu observer et chercher.
    Si tu es sous Linux tu as le "man" intégré sinon sur le Web tu as le "man en ligne", je te conseillerais de regarder dans string.h --> man string.h

    ^;

  5. #5
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 836
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

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

    Informations forums :
    Inscription : Février 2006
    Messages : 12 836
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Pasimple Voir le message
    un tableau avec comme cases chaque mois et une augmentation de +1 pour chaque ligne du mois rencontrée pendant la lecture du fichier.
    Yep

    Citation Envoyé par Pasimple Voir le message
    Du coup j'ai juste un tableau de 13 cases en tout (\o à la fin je crois)
    Non, pas besoin de 13 cases. La sentinelle (valeur spéciale qu'on place dans un tableau et qui permet de trouver où il se termine) sert pour les tableaux de taille variables pour lesquels on ne veut pas rajouter en plus une seconde variable pour gérer la taille. Exemple int tab[]={1, 3, 5, 12, 25, -1}. Si je veux afficher mon tableau, suffit de boucler jusqu'à -1. Et si je veux le faire évoluer, je n'ai pas besoin de me dire "zut faut pas oublier de modifier la variable qui stocke sa taille". Bref c'est fait pour simplifier la gestion.
    C'est par exemple le cas des strings qui sont des tableaux de caractères contenant une valeur 0 (qui peut se noter aussi 0x00 ou '\0' mais certainement pas '\o' et qu'il ne faut pas non plus confondre avec '0') quelque part. Pour afficher la string, suffit de partir du début et d'afficher tout ce qu'il y a jusqu'au '\0' (c'est pour ça qu'il faut qu'il y soit sinon c'est pas une string mais un simple tableau de char).

    Ici, la taille de ton tableau est connue. Il va gérer les mois. Il y a peu de chances qu'on fasse évoluer le calendrier pour lui rajouter d'autres mois dans un avenir proche. Tu peux alors présumer (balance risque de bug/coût de programmation pour s'en protéger) que dans ce cas, 12 est une valeur plutôt immuable pour ne pas avoir besoin de sentinelle.

    Citation Envoyé par Pasimple Voir le message
    J'ai aucune idée de comment je peux faire pour que le fichier soit analysé et que les chaînes de caractères des mois soient reconnus mais je vais essayer de trouver des ressources sur internet.
    Déjà as-tu le droit d'utiliser des fonctions déjà existantes du C? Si par exemple tu dois comparer deux chaines, as-tu le droit d'utiliser strcmp() ou bien te demande-t-on de tout coder? A mon avis je pense que certains outils te sont autorisés (c'est un projet, pas un exercice). Ainsi je te suggère de te pencher sur la fonction strstr()...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

Discussions similaires

  1. Réponses: 4
    Dernier message: 20/01/2013, 12h50
  2. Réponses: 8
    Dernier message: 03/01/2008, 16h00
  3. faire un logiciel qui fait parsing d'un fichier xml existant sur le serveur
    Par wajdiisi2007 dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 08/08/2007, 12h09
  4. comment faire un programme qui calcul la somme ?
    Par jahjouna dans le forum C++
    Réponses: 18
    Dernier message: 13/12/2006, 00h33
  5. Faire un programme qui plante et noter le plantage
    Par cedricgirard dans le forum Langage
    Réponses: 9
    Dernier message: 22/03/2006, 16h36

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