Lire une chaîne de caractère dans un fichier log en C

Fermé
Vaypp Messages postés 2 Date d'inscription samedi 4 décembre 2021 Statut Membre Dernière intervention 5 décembre 2021 - Modifié le 4 déc. 2021 à 21:48
 Azura - 19 janv. 2022 à 14:24
Bonjour à tous,

Je n'arrive pas à extraire des informations (en chaîne de caractère)
Exemple : Je veux savoir dans un fichier log le nombre de ligne ayant le mot "Nicolas". Et je veux écrire cette information dans une page WEB.

Voici un bout de mon code :

void LigneParNico(FILE*fic, FILE*fic1){

    fic=fopen("../log3.log","r");
    fic1=fopen("exemple.html","w");

    char nico[20];
    char lectureNico[20];

    int nbr_lignes=0;

    while(!feof(fic)){
        fscanf(fic,"%s",nico);
        printf("%s\n",nico);

        ++nbr_lignes;


        printf("%d\n",nbr_lignes);
            }
    printf("%d\n,",nbr_lignes);
    printf("%s",nico);
    fprintf(fic1, "<p>Il y a %d lignes ayant comme nico : %s \n</p>\n",nbr_lignes,nico);

    fclose(fic);
    fclose(fic1);
}


"fic" étant mon fichier log et "fic1" étant ma page.
Je comprends "l'erreur de mon fichier", il ne saute pas de ligne.

Quelqu'un pourrait-il m'aider ?
Bonne soirée,
Vayyp
A voir également:

6 réponses

[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
5 déc. 2021 à 01:12
Salut Vaypp,

Donne un exemple de ce que contient ton fichier de log et donne un exemple de ce que tu veux écrire dans ton fichier Web qui corresponde.

Ton code a de nombreux problèmes et incohérences par rapport à ce que tu dis vouloir faire. Ta boucle de lecture est erronée, car tu commences par vérifier feof() avant d'avoir commencé à lire. A aucun moment tu ne vérifies que ce que tu pourrais récupérer corresponde ou contienne le mot "Nicolas" ou autre chose. Utiliser fscanf() comme tu le fais est probablement dangereux à moins que tu connaisse avec certitude le contenu du fichier et que tu disposes de l'assurance que le texte récupéré avec %s ne dépassera jamais 19 char.

Pourquoi veux-tu faire cela en C ?

Sous Linux, en ligne de commande on ferais juste :

grep -o 'Nicolas' ../log3.log | wc -l


pour récupérer le nombre d'occurrences


Dal
1
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 5 déc. 2021 à 16:33
Du coup la boucle est vraiment simple et tient en 3 lignes :

        while (fgets(st, MAX_ST_LEN, fich_log) != NULL)
                if (strstr(st, SEARCH_STRING))
                        count++;



Dal
1
Vaypp Messages postés 2 Date d'inscription samedi 4 décembre 2021 Statut Membre Dernière intervention 5 décembre 2021
Modifié le 6 déc. 2021 à 12:21
Bonjour,

Je suis sous Windows.

Voici une partie de mon fichier log (exemple) :

[Nicolas Bonjour, moi je m'appelle Nicolas Dupont
[Nicolas Bonjour, moi je m'appelle Nicolas Dumont
[Nicolas Bonjour, moi je m'appelle Nicolas Duront
[Sylvie Bonjour, moi je m'appelle Sylvie Duront
...


En effet, je connais avec certitude mon fichier log.

Dans mon fichier Web, j'aimerais par exemple :
fprintf("Il y a %d lignes ayant le mot %s",NombreDeLigne,VariableDePrenom);


... qu'on sache le nombre de ligne ayant comme chaîne de caractère "Nicolas"

Je pense qu'il est possible de donner le nombre de ligne ayant comme chaîne de caractère "Nicolas".

Merci pour ton aide,

Vaypp
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 5 déc. 2021 à 14:10
Bonjour,

En effet, c'est possible, et il y a de nombreuses façons de faire en C. Mais, même sous WIndows c'est bien plus facile à faire qu'en C, par exemple avec PowerShell :

gc ../log3.log | % { ($_ | Select-String -Pattern Nicolas -all).matches | measure | select count }

(non testé, je suis sous Linux)

Tu n'expliques pas pourquoi tu veux le faire en C.

Connais-tu la longueur maximale de tes lignes ?

Si oui, je te recommanderai de le faire plutôt avec fgets() qui te permettra de lire des lignes entières :

https://www.cplusplus.com/reference/cstdio/fgets/

et rechercher ensuite la sous-chaine "Nicolas" dans chaque ligne avec strstr() :

https://www.cplusplus.com/reference/cstring/strstr/

si strstr() retourne un résultat, elle va retourner un pointeur vers l'adresse où se trouve la sous-chaîne (sinon elle retourne NULL), pour voir s'il y a d'autres "Nicolas" sur la même ligne, il suffit de réitérer la recherche à partir de l'adresse du char suivant.

tu fais cela en incrémentant un compteur jusqu'à ce que tu aies traité toutes tes lignes et tu obtiens le nombre de "Nicolas".
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083 > [Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024
Modifié le 5 déc. 2021 à 16:28
Hmm, non, en fait c'est moins compliqué que cela, car tu veux savoir le nombre de lignes contenant le mot "Nicolas" et non pas combien de fois le mot Nicolas apparaît dans le fichier.

J'avais lu trop rapidement, désolé.

Tu as juste une boucle à faire et si strstr() renvoie quelque chose, tu incrémentes, et tu passes à la ligne suivante.

fgets() est d'autant plus adaptée à ton cas, car tu cherches les lignes matchant le mot.
0
Bonjour,
Tout d'abord, je tiens a m'excuser pour ma réponse tardive... quelques problèmes..

Un grand merci Dal, cependant, à quoi correspond "st" ? La chaine de caractère (buffer) ?
MAX_ST_LEN correspond à la taille de mon fichier je pense.
fich_log correspond au nom de mon fichier log
count correspond pour moi à ma variable nbr_lignes.

Donc si j'essaie de reprendre ta boucle, cela donne :

#define MAX_ST_LEN 2000
.
.
.
while (fgets(nico, MAX_ST_LEN, fic) != NULL)
                if (strstr(nico, "Nicolas"))
                        nbr_lignes++;


Merci encore,

Vaypp
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
13 déc. 2021 à 19:26
De rien Vaypp, je suis content si cela t'aide.

st, qui est le 1er paramètre de fgets() dans mon code, est le buffer où est lue chaque ligne.

Le 2ème paramètre de fgets() est le nombre maximal de char à lire pour chaque ligne, qui seront copiés dans le buffer, y compris le caractère terminateur '\0'. Ce n'est donc pas la taille totale du fichier, mais la taille maximale d'une ligne plus 1. Si tu as la garantie que tu as des lignes de 20 char au plus, met au moins 21 et dimensionne le buffer passé en 1er paramètre en conséquence (ou utilise un buffer et un nombre largement plus grand).

La page de documentation sur fgets() t'aurait indiqué tout cela : https://www.cplusplus.com/reference/cstdio/fgets/

Lit la documentation des fonctions standard du C, sinon tu fais les choses au hasard et ce n'est jamais bon en C.

Bon courage !
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083 > [Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024
14 déc. 2021 à 11:38
juste une précision : en fait, avec
fgets()
, il faut au moins un buffer de 22 char pour une ligne de 20 chars visibles dans ton fichier, car cette ligne lue à partir du fichier comprend en réalité un 21ème char qui est un caractère de retour à la ligne
'\n'
et qui est capturé par
fgets()
. Donc en plus du char terminateur nécessaire, il faut réserver un deuxième char en plus pour pouvoir loger le
'\n'
de fin de ligne (à moins que tu l'aies déjà compté).

D'ailleurs, c'est un moyen dont tu disposes de vérifier que la lecture avec
fgets()
a bien pris la totalité du contenu d'une ligne : le dernier char récupéré doit être
'\n'
.

Si tu n'est pas à quelques dizaines de bytes près, alors comme indiqué ci-dessus, tu ne devrais pas te priver d'utiliser un buffer largement plus grand.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Bonjour

J'ai lu la conversation juste au dessus et cela m'a permis de pouvoir compter le nombre de fois où j'ai une date est dans une ligne

Quand j'exécute mon programme en C le résultat affiché est: Il y'a 21 lignes avec la date du 13/Feb/2021

Seulement mon problème est que je souhaite avoir cette phrase avec toutes les dates différentes de mon fichier .log et qu'il soit affiché dans ma console

Deplus cette phrase est écrite dans un fichier .html

Voici mon code:
void liredate(FILE *f,char date1[ ])
{
FILE *site;
site=fopen("site.html","a+");
f=fopen("logapache.log","rt");
char *buffer = (char *)malloc(MAX_LENGTH);
int c, count=1;
fprintf(site,"<br/>Les dates sont : <br/>");
fscanf(f,"%*s %*s %*s [%s ",date1);
date1[11] = '\0';
while((c=fgetc(f)) != EOF){
while (fgets(buffer, MAX_LENGTH, f) != NULL)
if (strstr(buffer, date1))
count++;
}
printf("Il y a %d lignes ayant la date %s\n",count, date1);
fprintf(site,"Il y a %d lignes ayant la date %s\n",count, date1);
fclose(site);
fclose(f);


Merci de votre aide.
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 19 janv. 2022 à 10:39
Salut Azura,

Si je me fie à tes spécificateurs de scanf() : ,
"%*s %*s %*s [%s "
et que j'en déduis que tes dates se trouvent toujours dans une ligne :
  • commençant par un suite de caractères "non blancs" (ni espace, ni tabulation ou retour à la ligne), appelons cela un Mot, que tu ignores, suivi d'un espace
  • suivi d'un autre Mot que tu ignores aussi, suivi d'un espace
  • suivi d'un autre Mot que tu ignores aussi, suivi d'un espace
  • suivi d'un crochet ouvrant
  • suivi d''un Mot qui contient toujours ta date (laquelle ne contient pas de caractères "blancs"), que tu n'as pas besoin de valider le contenu de ce Mot et que celui-ci est suivi d'un espace
  • et en supposant que si la ligne contient une date, il n'y a qu'une date à rechercher sur cette ligne


Alors, le code suivant récupère effectivement ce Mot à cet emplacement :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
        char st[255] = "truc machin bidule [13/Feb/2021 12:34] suite autres bidules\n";
        char date[255];
        if (sscanf(st, "%*s %*s %*s [%s ", date) == 1)
                printf("date = %s\n", date);
        else
                printf("Cette ligne ne contient pas ce que je cherche");
        return 0;
}


donne :

$ gcc -Wall -Wextra 37443731.c 
$ ./a.out
date = 13/Feb/2021


Par contre ton code dans la fonction
void liredate(FILE *f,char date1[ ]) 
n'a pas de sens pour moi par rapport à ce que tu dis vouloir faire (elle devrait d'ailleurs s'appeler autrement, par exemple
compter_dates()
et son prototype n'est pas cohérent).

Après avoir ouvert ton fichier log en lecture, et ton fichier .html en écriture, tu devrais :

1. lire une ligne avec
fgets()
en t'assurant qu'une ligne complète a bien été lue (le dernier char de la chaîne doit être un '\n')
2. passer la ligne ainsi récupérée sur
sscanf(st, "%*s %*s %*s [%s ", date);
pour récupérer la date et contrôler la valeur de retour de
sscanf()
pour vérifier qu'elle a bien récupéré 1 élément
3. incrémenter un compteur, puis boucler sur 1.
4. lorsque toutes les lignes du fichier log ont été lues, tu fermes tes deux fichiers
5. tu affiches ton message indiquant combien de fois une date quelconque a été trouvée (et non pas ce que tu affiches).

D'ailleurs, il serait mieux que ta fonction retourne ce nombre (et laisse le soin à la fonction appelante de passer les noms des fichiers concernés, ou des pointeurs vers des fichiers déjà ouverts), afin de dissocier le traitement de l'affichage.

Lorsque tu postes ton code sur le forum, poste le correctement stp avec les balises de code du forum en choisissant le langage "c". Vois ces instructions si tu ne vois pas de quoi je parle : https://codes-sources.commentcamarche.net/faq/11288-les-balises-de-code
0
Bonjour

En effet ma ligne de code avec les %s me permet et indique que la date se situe plus loin cependant quand je récupère ton code celui-ci me lit la ligne et indique que ce que je lui met entre crochet, j'aimerai si possible savoir comment mettre la variable date dans ce code.

Ensuite voici mon code qui vérifie que mon fichier est bien ouvert, et après celui-ci il y'a le code qui permet de lire la date à l'endroit ou je souhaite sauf qu'il m'affiche ce qu'il y'a écrit entre crochet comme je te l'ai dit précédemment.
void extrairedate(FILE *f)
{       int c;
        char mystring [100];
        {
            if (f == NULL) perror ("Error opening file");
            else {
            if ( fgets (mystring , 100 , f) != NULL )
                    puts (mystring);
                }
        }
        int count=1;
        char *buffer = (char *)malloc(MAX_LENGTH);
        char st[255] = "truc machin bidule [Date\0] suite autres bidules\n";
        char date[255];
        while((c=fgetc(f)) != EOF)
        if (sscanf(st, "%*s %*s %*s [%s ", date) == 1)
                printf("date = %s\n", date);
        else
            printf("Cette ligne ne contient pas ce que je cherche");
        fclose (f);
        return 0;
}

Si j'ai bien compris le code il suffirait de savoir la date à extraire mais malheureusement si une date s'ajoute dans mon fichier log avec la même ligne il ne sera donc pas capable de la lire :/

Je suis très mauvais en C vraiment c'est assez compliqué de pouvoir réaliser cette tâche
Merci beaucoup pour ton aide Dal
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083
Modifié le 19 janv. 2022 à 11:26
Désolé, mais ce que tu écris n'est vraiment pas clair pour moi.

Le mieux est :
  • que tu montres une ligne type de ton fichier de log qui contient la date que tu cherches
  • que tu dises exactement la partie qui t'intéresse et celles qui ne t'intéressent pas
  • que tu montres une ligne où la date ne se trouve pas


Si le langage C est compliqué pour toi, pourquoi ne le fais tu pas dans un autre langage ?

En Perl ou en Python, cela doit se faire en 5 lignes.
0
Azura > [Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024
19 janv. 2022 à 11:32
Re
Voici quelques lignes de mon fichier log, toutes les informations se trouvent à la même place, de plus j'aimerai beaucoup le faire dans un autre langage, car énormément de personne me conseil de faire cette chose dans un langage ou cela est bien plus pratique mais malheureusement je ne peux pas
Ensuite je suis l'ami de Vaypp la personne que tu as aidé précédemment mais il n'a pas le même fichier log et donc pas la même structure.

::1 - - [14/Feb/2021:23:54:16 +0100] "GET /public/enseignement.php HTTP/1.1" 200 4793
::1 - - [14/Feb/2021:23:54:17 +0100] "GET /style/styleSitePro.css HTTP/1.1" 304 -
::1 - - [14/Feb/2021:23:55:16 +0100] "-" 408 -
::1 - - [15/Feb/2021:09:35:27 +0100] "GET /public/enseignement.php HTTP/1.1" 200 4793
::1 - - [15/Feb/2021:09:35:27 +0100] "GET /style/styleSitePro.css HTTP/1.1" 304 -

Merci
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083 > Azura
19 janv. 2022 à 11:36
Merci.

Tu n'as pas répondu aux demandes suivantes :
  • que tu dises exactement la partie qui t'intéresse et celles qui ne t'intéressent pas
  • que tu montres une ligne où la date ne se trouve pas
0
Azura > [Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024
19 janv. 2022 à 11:40
Oh mince excuse moi
Ce qui m’intéresse ici c’est d’avoir la date de toutes les lignes étant donné qu’elles sont différentes à certaines lignes je souhaiterai les récupérer et ensuite les stocker et être capable de savoir combien de fois j’ai la même date sur le nombre de lignes de mon fichier log

Merci beaucoup
0
[Dal] Messages postés 6174 Date d'inscription mercredi 15 septembre 2004 Statut Contributeur Dernière intervention 2 février 2024 1 083 > Azura
19 janv. 2022 à 13:52
donc, par exemple, pour ce que tu as posté, tu voudrais avoir :


14/Feb/2021 3 fois
15/Feb/2021 2 fois


C'est cela ?

Ce que tu veux, en fait c'est : pour chaque date unique (jour, mois, année) présente dans les logs, recenser combien de lignes contiennent cette date dans ton fichier de logs (en ignorant les informations concernant l'heure), et pouvoir établir la liste des dates uniques et le nombre de lignes où chacune apparaît.

Je suppose :
  • qu'en fait toutes les lignes ont une date (c'est la 3ème fois que je te demande de confirmer s'il y a des lignes qui n'en ont pas, j'ai atteint mon quota), qu'elle est entre crochets comme présenté et toujours précédée de
    "::1 - - ["
    et qu'elle se termine au premier char ':' qui suit
  • que les dates sont dans l'ordre chronologique
  • que tu peux déterminer une taille maximale de tes lignes


Si les dates sont dans l'ordre chronologique, tu n'as pas besoin de stocker toutes les dates en mémoire pour décompter le nombre de dates uniques, tu peux juste les écrire au fur et à mesure lorsque la date change et que tu as le décompte correspondant à la date précédente. Il te faut juste stocker la date précédente avant le lire la suivante, pour pouvoir les comparer et traiter ton fichier.

C'est assez facile à faire.

Avez ces indications, as-tu besoin de plus d'aide ?
0