[C] extraire partie d'un fichier texte

vincent02 Messages postés 9 Date d'inscription   Statut Membre Dernière intervention   -  
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   -
Bonjour,

Je dois faire quelque chose qui m'a pas l'air très dur mais malheuresement, je n'ai pas la moindre idée de la manière de procéder,

J'ai un fichier textes composés d'une succession de chaines de caractères comme celle ci :

16:26:28 (9.50 MB/s) - `MEGASAVE.tar.gz.14' saved [942668/942668]
16:26:46 (9.60 MB/s) - `MEGASAVE.tar.gz.15' saved [942668/942668]

Mille plus précisément et je souhaite juste extraire 9.50 MB/s et 9.60 MB/s...meme pas dans un tableau, juste récuperer les valeurs...

Je ne connais pas les pointeurs. donc il me faudrait qqchose d'assez simple.

Merci infiniment,

Mon adresse email est vincent_roye@hotmail.com
A voir également:

12 réponses

arth Messages postés 9374 Date d'inscription   Statut Contributeur Dernière intervention   1 293
 
apparement tu as plusieurs chaines de caractères séparées par des espaces blancs.

ce que je te conseille c'est de définir une chaine pour chaque element, douvrir ton fichier et d'effectuer un

fscanf("%s %s %s %s %s %s %s %s ...",nom des tableau correspondant);

apres tu regarde si le tbleau contenant la chaine du debit est equivalente a une chaine fixe.

Si tu ne comprend pas je texpliquerais avec un exemple.
1
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
Pas d'adresse mail sur le forum s'il vous plaît (enfin moi je dis ça surtout pour toi :p) !

Tu peux aussi faire des trucs de ce genre : tu veux extraire le chiffre 6 dans la chaine "plop 6" :

char *str="plop 6";
int x;
sscanf(str,"plop %d",&x);

arth a oublié de passer le fichier en paramètre du fscanf. Tu peux consulter l'aide ici :
http://www.linux-france.org/article/man-fr/man3/scanf-3.html

Tu peux t'inspirer de ce post pour voir comment lire un fichier ligne par ligne :
https://forums.commentcamarche.net/forum/affich-2234751-c-parsing-d-un-fichier


Si tu es motivé tu peux utiliser aussi la lib pcre.

Ceci dit il y a des langages plus adapté que le C/C++ pour parser des fichiers à l'aide d'expressions régulières, comme le python, le ruby, ou le perl...

Bonne chance
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
Salut,

Ceci dit il y a des langages plus adapté que le C/C++ pour parser des fichiers à l'aide d'expressions régulières, comme le python, le ruby, ou le perl...

mamiemando a raison et c'est vraiment simple.

En revanche travailler sur un petit morceau de fichier ce n'est pas evident.

Si je travailler sur tes lignes (j'ai écrit le code à la volée - donc je n'ai pas tester, je le ferai quand j'arriverai à la maison dans 1h30, mais tu peux le faire jusqu'à là)

16:26:28 (9.50 MB/s) - `MEGASAVE.tar.gz.14' saved [942668/942668] 
16:26:46 (9.60 MB/s) - `MEGASAVE.tar.gz.15' saved [942668/942668] 


Je vais affichier seulement le résultat
#!/usr/bin/perl
#
use warnings;use strict;


# les lignes je les ajoute dans le script après le token __END__
# je lis __END__ avec le handle DATA et j'affiche a l'écran les valeurs
#
while (<DATA>){
	print "$1\n" if /.*\((.*)\).*/;
}
__END__
16:26:28 (9.50 MB/s) - `MEGASAVE.tar.gz.14' saved [942668/942668] 
16:26:46 (9.60 MB/s) - `MEGASAVE.tar.gz.15' saved [942668/942668] 
lami20j

P.S. Le code ne fonctionne que sur les 2 lignes ou sur le nombre des lignes que la mémoire peut supporter si la structure est toujours la même
0
jipicy Messages postés 40842 Date d'inscription   Statut Modérateur Dernière intervention   4 896
 
Ceci dit il y a des langages plus adapté que le C/C++ pour parser des fichiers à l'aide d'expressions régulières, comme le python, le ruby, ou le perl...

mamiemando a raison et c'est vraiment simple.


D'autant plus que la solution lui avait déjà été donnée là :
https://forums.commentcamarche.net/forum/affich-2235053-programmation-bash-debutant-recuperer-donne#0
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
Salut,

en plus j'ai vu le message (où il y a bash il y a jipicy, mais c'est Dal qui a été plus rapide).

Bon week-end,

lami20j
0

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

Posez votre question
arth Messages postés 9374 Date d'inscription   Statut Contributeur Dernière intervention   1 293
 
quoi arth qu'est ce qu'il a arth c'est ma piste qui te plait pas? bah répond plus souven alors ne faiis pas que le ménage.
0
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
C'est améliorable en catchant les numéros avec un \d... Idéalement tu peux même écrire ton expression régulière en vérifiant que les numéros passés entre chaque point ne sont pas trop absurdes.

Ceci dit je trouve qu'il serait intéressant de décrire un peu pourquoi l'expression régulière marche même si les généralités doivent déjà figurer dans la base de connaissance... Uniquement dans un but pédagogique ou pour illustrer ces notions avec des exemples concrets.

Bonne chance
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
Salut,

Ceci dit je trouve qu'il serait intéressant de décrire un peu pourquoi l'expression régulière marche même si les généralités doivent déjà figurer dans la base de connaissance... Uniquement dans un but pédagogique ou pour illustrer ces notions avec des exemples concrets.


Je ne sais pas si t'es adressé à moi mais je vais le faire, avec des exemples et aussi dans l'esprit TMTOWTDI

lami20j
0
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
C'était adressé à qui est motivé pour décrypter une expression regulière de perl... c'est-à-dire pas moi ;)
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
Ok, pas de problèmes.

a+

lami20j
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
Re,

j'ai utilisé toujours les 2 lignes données au début de messages.

il y a toujours la posibilité de modifier ou de créer une autre regex.

je n'ai pas non plus imaginé d'autres situations, c'est un peu tard et je suis un peu parreseux.

avec l'espoir que je ne te deçois pas, voilà ce que ça donne mamiemando
#! /usr/bin/perl

use warnings;use strict;
# toujours je vais utiliser le handle DATA

# 1. utilisation de quantificateur gurmand *

while (<DATA>){
  print "1. $1\n" if /.*\((.*)\).*/;
  # dans ce cas j'utilise une regex banale
  # .* prend n'importe quel caractère 0,1 fois ou ......
  # en bref en premier temps .* va avaler tout
  # ensuite sous contrainte va ceder un par un chaque caractère
  # jusqu'à quand il trouve la 1ère paranthèse
  # .* entre paranthèse va faire la même chose mais il sera
  # de ceder aussi la paranthèse fermante
  # comme ( et ) sont des metacaractères qui servent au groupement et capture
  # j'ai utilsé \ pour les trouver littéralement
  # le dernier .* ne sers pas à grand chose (donc on peut s'abstenir)
#}

#2. utilisation de la classe de caractères \d qui est équivalente avec [0-9]
print "2. $1\n" if /
      \d\d:\d\d:\d\d        # regex reconnaît 16:26:28
      \s*                   # ensuite 0,1 ou n'importe combien d'espaces
      \(                    # une paranthèse littérale
      (                     # debut du capture, ici la paranthèse = bestiole regex
        \d\.\d\d\s*MB\/s    # reconnaît une chiffre suit d'un point suit de 2 chiffres
                            # de 0,1 ou plusierus espaces suit de M suit de B suit de slash suit de s
      )                     # fin de la capture
      \)/x;                 # paranthèse littérale
                            # la regex: /\d\d:\d\d:\d\d\s*\((\d\.\d\d\s*MB\/s)\)/
                            #le modificateur x permet d'utiliser des espaces
                            # et des commentaires à l'intérieur de regex

#3. utilisation de la classe \d avec quantificateurs {x,y}

print "3. $1\n" if /
      \d{1,2}:\d{1,2}:\d{1,2} # regex reconnaît 16:26:28
                              # {1,2} veut dire 1 ou 2 chiffres
      \s*                     # ensuite 0,1 ou n'importe combien d'espaces
      \(                      # une paranthèse littérale
        (                     # debut du capture, ici la paranthèse = bestiole regex
        \d\.\d{1,2}\s*MB\/s   # reconnaît une chiffre suit d'un point suit de 2 chiffres
                              # de 0,1 ou plusierus espaces suit de M suit de B suit de slash suit de s
        )                     # fin de la capture
      \)/x;                   # paranthèse littérale
                              #le modificateur x permet d'utiliser des espaces
                              # la regex: /\d{1,2}:\d{1,2}:\d{1,2}\s*\((\d\.\d{1,2}\s*MB\/s)\)/
                              #le modificateur x permet d'utiliser des espaces
                              # et des commentaires à l'intérieur de regex

#4. Utilisation d'une classe complementé [^...]

print "4. $1\n" if /
                  \(          # paranthèse littérale
                    (         # début de la capture
                      [^()]+  # reconnaît au moins une fois tout caractère qui
                              # n'est ni ( ni )
                    )         # fin de la capture
                  \)/x;       # paranthèse littérale
                              #la regex: /\(([^()]+)\)/

#5. utilisation de test avant (?=motif) et test arrière (?<=motif)

print "5. $1\n" if /
                      (?<=    # début test arrière
                          \(  # on cherche en arrière une paranthèse littérale ouvrante
                      )       # fin test arrière
                        (.*)  # on capture si en arrière il y une ( et si avant il ya )
                      (?=     # debut test avant
                          \)  # on cherche en avant une )
                      )/x;    # fin de test avant
                              # la regex: /(?<=\()(.*)(?=\))/

#6. utilisation d'une variable et substitution

  (my $tmp = $_) =~ s/.*\(([^()]+)\).*/$1/; # même regex que 4.
  print "6. $tmp\n";
}
__END__
16:26:28 (9.50 MB/s) - `MEGASAVE.tar.gz.14' saved [942668/942668]
16:26:46 (9.60 MB/s) - `MEGASAVE.tar.gz.15' saved [942668/942668]
Le résultat
[lamitest@localhost my_perl_script]$ perl mamiemando.pl
1. 9.50 MB/s
2. 9.50 MB/s
3. 9.50 MB/s
4. 9.50 MB/s
5. 9.50 MB/s
6. 9.50 MB/s

1. 9.60 MB/s
2. 9.60 MB/s
3. 9.60 MB/s
4. 9.60 MB/s
5. 9.60 MB/s
6. 9.60 MB/s

[lamitest@localhost my_perl_script]$
lami20j
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
Re,

Voilà le script sans commentaires
#! /usr/bin/perl

use warnings;use strict;
# toujours je vais utiliser le handle DATA

while (<DATA>){

# 1. utilisation de quantificateur gurmand *
print "1. $1\n" if /.*\((.*)\).*/;

#2. utilisation de la classe de caractères \d qui est équivalente avec [0-9]
print "2. $1\n" if /\d\d:\d\d:\d\d\s*\((\d\.\d\d\s*MB\/s)\)/;

#3. utilisation de la classe \d avec quantificateurs {x,y}

print "3. $1\n" if /\d{1,2}:\d{1,2}:\d{1,2}\s*\((\d\.\d{1,2}\s*MB\/s)\)/;

#4. Utilisation d'une classe complementé [^...]

print "4. $1\n" if /\(([^()]+)\)/;

#5. utilisation de test avant (?=motif) et test arrière (?<=motif)

print "5. $1\n" if /(?<=\()(.*)(?=\))/;

#6. utilisation d'une variable et substitution

  (my $tmp = $_) =~ s/.*\(([^()]+)\).*/$1/; # même regex que 4.
  print "6. $tmp\n";
}
__END__
16:26:28 (9.50 MB/s) - `MEGASAVE.tar.gz.14' saved [942668/942668]
16:26:46 (9.60 MB/s) - `MEGASAVE.tar.gz.15' saved [942668/942668]
lami20j
0
vincent02 Messages postés 9 Date d'inscription   Statut Membre Dernière intervention  
 
Re,

J ai reussi a le faire marcher maintenant je cherche juste un moyen de stocker le resultat dans un fichier resultado3.txt au lieu de le printer a l ecran, je ne comprend pas la ligne suivante non plus :(

print "$1\n" if /.*\((.*)\).*/;

merci beaucoup pour ton aide
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570 > vincent02 Messages postés 9 Date d'inscription   Statut Membre Dernière intervention  
 
Salut,

pour enregister dans un fichier tu peux utiliser une rédirection

perl script.pl > resultat.txt

En ce qui concerne

print "$1\n" if /.*\((.*)\).*/;

Dans perl idiomatique on peut dire tout simplement fait moi ça si la condition est rempli.

Ex.

affiche si nombre plus grand que 1
print if $nombre >1

pour la regex regarde dans le message 11

lami20j
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
Re,

j'ai pensé aussi d'utiliser le mode slurp et l'assertion \G, mais c'était trop tard (ou trop tôt).
#! /usr/bin/perl

use warnings;use strict;

# mode slurp
# permet d'avaler le contenu de DATA dans une variable scalaire
# ce qui permet l'utilisation de l'assertion \G

undef $/; # $/ ou $INPUT_RECORD_SEPARATOR ou $RS
          # c'est le séparateur d'entrée, par défaut \n
          # est consulté par la fonction readline,
          # l'operateur <HANDLE> et la fonction chomp
my $txt = <DATA>; # tous le contenu de DATA

pos($txt) = 0; # \G est initialisé à 0
while ($txt =~ /\(/g){
  print "$1\n" if $txt =~ /\G(.*)\)/;
}
#/\(/g) detecte une paranthèse ouvrante progressivement

# /\G(.*)\)/

# /\G(.*) capture dans $1 ce que je trouve après la paranthèse ovrante
# \)/ jusqu'à on rencontre une paranthèse fermante

# ce cycle se repete jusqu'à la fin de contenu de $txt

__END__
16:26:28 (9.50 MB/s) - `MEGASAVE.tar.gz.14' saved [942668/942668]
16:26:46 (9.60 MB/s) - `MEGASAVE.tar.gz.15' saved [942668/942668]
lami20j
0
vincent02 Messages postés 9 Date d'inscription   Statut Membre Dernière intervention  
 
Re,

j'ai pensé aussi d'utiliser le mode slurp et l'assertion \G, mais c'était trop tard (ou trop tôt).

#! /usr/bin/perl

use warnings;use strict;

# mode slurp
# permet d'avaler le contenu de DATA dans une variable scalaire
# ce qui permet l'utilisation de l'assertion \G

undef $/; # $/ ou $INPUT_RECORD_SEPARATOR ou $RS
# c'est le séparateur d'entrée, par défaut \n
# est consulté par la fonction readline,
# l'operateur <HANDLE> et la fonction chomp
my $txt = <DATA>; # tous le contenu de DATA

pos($txt) = 0; # \G est initialisé à 0
while ($txt =~ /\(/g){
print "$1\n" if $txt =~ /\G(.*)\)/;
}
#/\(/g) detecte une paranthèse ouvrante progressivement

# /\G(.*)\)/

# /\G(.*) capture dans $1 ce que je trouve après la paranthèse ovrante
# \)/ jusqu'à on rencontre une paranthèse fermante

# ce cycle se repete jusqu'à la fin de contenu de $txt

__END__
16:26:28 (9.50 MB/s) - `MEGASAVE.tar.gz.14' saved [942668/942668]
16:26:46 (9.60 MB/s) - `MEGASAVE.tar.gz.15' saved [942668/942668]

lami20j


Merci beaucoup. le probleme est que je ne sais pas comment ouvrir mon fichier texte ou il y a les lignes que veux traiter. Il faut les mettre dans DATA et le fichier est dans le repertoire /home/vincent/amigos/resultado2.txt
je ne sais pas non plus comment je pourrai avoir mon fichier de sortie traité.

merci encore
0
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
C'est nickel ^^ Bravo lami20j
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
Un bravo de la part d'une personne comme toi, dit beaucoup des choses.
Merci.

lami20j
0
mamiemando Messages postés 33778 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 
:) Je vais rougir ^^
0
lami20j Messages postés 21331 Date d'inscription   Statut Modérateur, Contributeur sécurité Dernière intervention   3 570
 
Pour des raisons de discretion je ne peux pas expliquer mon message N°15, et je n'écrit jamais seulement pour écrire.

Heureusement que le rougissement ne fait pas du mal, au contraire.

Bonne journée,

lami20j
0