Rechercher : dans
Par :

[C] extraire partie d'un fichier texte

Dernière réponse le 23 mai 2006 à 15:52:04 vincent02, le 19 mai 2006 à 20:03:28 
 Signaler ce message aux modérateurs

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

Meilleures réponses pour « [C] extraire partie d'un fichier texte » dans :
[MS-Dos] Ecrire dans un fichier texte en batch VoirPour écrire dans un fichier texte, il suffit d'utiliser une redirection ">" : echo texte_à_ecrire > fichier_de_sortie.txt Pour écrire à la fin d'un texte existant (concaténation) : echo "écriture a la fin du fichier ">>...
Qu'est-ce qu'un fichier? VoirQu'est-ce qu'un fichier? Un fichier est une suite d'informations binaires, c'est-à-dire une suite de 0 et de 1. Ce fichier peut être stocké pour garder une trace de ces informations. Un fichier texte est un fichier composé de caractères stockés...
Fichier TXT VoirFormat TXT Un fichier TXT est un fichier texte, c'est-à-dire un simple fichier contenant du texte au format ASCII. Pour ouvrir ou modifier un tel fichier, il suffit d'utiliser le bloc-notes ou un éditeur de texte traditionnel.

1

arth, le 19 mai 2006 à 20:11:56

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.

Répondre à arth

2

mamiemando, le 19 mai 2006 à 20:49:22

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 :
http://www.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

Répondre à mamiemando

3

lami20j, le 19 mai 2006 à 21:18:12

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

Répondre à lami20j

4

jipicy, le 19 mai 2006 à 23:30:07

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à :
http://www.commentcamarche.com/forum/affich-2235053-programm­ation-bash-debutant-r...
Z'@+...che.

JP : Zen, my Nuggets ! ;-)
Le savoir n'est bon que s'il est partagé.

Répondre à jipicy

6

lami20j, le 19 mai 2006 à 23:32:45

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

Répondre à lami20j

5

arth, le 19 mai 2006 à 23:31:52

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.

Répondre à arth

7

mamiemando, le 20 mai 2006 à 00:37:40

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

Répondre à mamiemando

8

lami20j, le 20 mai 2006 à 00:42:04

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

Répondre à lami20j

9

mamiemando, le 20 mai 2006 à 00:48:25

C'était adressé à qui est motivé pour décrypter une expression regulière de perl... c'est-à-dire pas moi ;)

Répondre à mamiemando

10

lami20j, le 20 mai 2006 à 00:49:53

Ok, pas de problèmes.

a+

lami20j

Répondre à lami20j

11

lami20j, le 20 mai 2006 à 02:38:26

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

Répondre à lami20j

12

lami20j, le 20 mai 2006 à 02:48:53

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

Répondre à lami20j

19

vincent02, le 23 mai 2006 à 14:14:12

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

Répondre à vincent02

20

 lami20j, le 23 mai 2006 à 15:52:04

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

Répondre à lami20j

13

lami20j, le 20 mai 2006 à 15:42:42

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

Répondre à lami20j

18

vincent02, le 23 mai 2006 à 13:47:55

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

Répondre à vincent02

14

mamiemando, le 21 mai 2006 à 00:16:42

C'est nickel ^^ Bravo lami20j

Répondre à mamiemando

15

lami20j, le 21 mai 2006 à 10:08:58

Un bravo de la part d'une personne comme toi, dit beaucoup des choses.
Merci.

lami20j

Répondre à lami20j

16

mamiemando, le 21 mai 2006 à 12:40:00

:) Je vais rougir ^^

Répondre à mamiemando

17

lami20j, le 21 mai 2006 à 12:54:29

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

Répondre à lami20j