Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
2666 connectés 

  FORUM HardWare.fr
  Programmation
  C

  Existe-t-il une fonction qui cherche dans un flux ?

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Existe-t-il une fonction qui cherche dans un flux ?

n°1299767
e-miel
Posté le 06-02-2006 à 13:28:42  profilanswer
 

Existe-t-il une fonction (que j'ai appelée fchercher dans l'exemple ci-dessous) qui lit un flux jusqu'à tomber sur une chaîne particulière :

int truc, chose, bidule ;
 
FILE *f = popen("commande", "r" ) ;
 
fchercher(f, " truc=" ) ;
fscanf(f, "%i", &truc) ;
 
fchercher(f, " chose=" ) ;
fscanf(f, "%i", &chose) ;
 
fchercher(f, " bidule=" ) ;
fscanf(f, "%i", &bidule) ;
 
pclose(f) ;


 
Pour l'instant, je copie tout dans un buffer, ce qui me permet de chercher les champs avec strstr. Sachant que les noms des champs ne sont pas aussi évidents que dans l'exemple ci-dessus, et qu'il y a pas mal de champs, mon code source est donc difficile à comprendre pour le premier venu. En plus, la majeure partie du texte qui sort de "commande" ne m'intéresse pas... j'ai donc tout intérêt à utiliser une fonction semblable à fchercher, ce qui m'évitera d'allouer un gros buffer pour si peu.
 
Que me conseillez-vous ?

mood
Publicité
Posté le 06-02-2006 à 13:28:42  profilanswer
 

n°1299773
Sebou77
French Tech powaa :-)
Posté le 06-02-2006 à 13:33:57  profilanswer
 

j'ai pas bien compris :/
strcmp ne t'aiderai pas ?

n°1299784
Elmoricq
Modérateur
Posté le 06-02-2006 à 13:49:04  profilanswer
 

Je te conseille de placer la liste de tes champs dans un tableau de caractères (dans le fichier en-tête, par exemple, ou dans la fonction même, à toi de voir), et de stocker les résultats dans un tableau dynamiquement alloué.
 
Comme ça, au lieu de répéter n fois la même séquence de commandes, tu écris une boucle.
 
Genre :

const char *l_field[] = { "truc", "chose", "bidule", NULL };
unsigned i = 0;
const char *field = l_field[i];
 
while ( field ) {
   ...
   field = l_field[++i];
}


Message édité par Elmoricq le 06-02-2006 à 13:50:08
n°1299832
Sve@r
Posté le 06-02-2006 à 14:52:29  profilanswer
 

e-miel a écrit :

Existe-t-il une fonction (que j'ai appelée fchercher dans l'exemple ci-dessous) qui lit un flux jusqu'à tomber sur une chaîne particulière :

int truc, chose, bidule ;
 
FILE *f = popen("commande", "r" ) ;
 
fchercher(f, " truc=" ) ;
fscanf(f, "%i", &truc) ;
 
fchercher(f, " chose=" ) ;
fscanf(f, "%i", &chose) ;
 
fchercher(f, " bidule=" ) ;
fscanf(f, "%i", &bidule) ;
 
pclose(f) ;


 
Pour l'instant, je copie tout dans un buffer, ce qui me permet de chercher les champs avec strstr. Sachant que les noms des champs ne sont pas aussi évidents que dans l'exemple ci-dessus, et qu'il y a pas mal de champs, mon code source est donc difficile à comprendre pour le premier venu. En plus, la majeure partie du texte qui sort de "commande" ne m'intéresse pas... j'ai donc tout intérêt à utiliser une fonction semblable à fchercher, ce qui m'évitera d'allouer un gros buffer pour si peu.
 
Que me conseillez-vous ?


 
Ben le problème, c'est dans ton flux. Comment peux tu dire où s'arrête "bidule"
Exemple: Le flux contient "azertybidule=totowxcvbntruc=azertyxcvbvb"
Tu cherches "bidule=" et tu trouves "toto.....". Où t'arrêter ???
 
Faut d'abord que tu connaisses la structure de ton flux et ensuite tu peux te construire ta fonction "fchercher". Mais une telle fonction n'existe pas en natif puisqu'on ne peut pas prévoir à l'avance la tête de ton flux...

n°1300041
e-miel
Posté le 06-02-2006 à 19:08:22  profilanswer
 

Sve@r a écrit :

Comment peux tu dire où s'arrête "bidule"

Facile : j'attends des entiers, et scanf sait très bien s'arrêter là où il faut, du moment qu'on lui montre exactement là où il doit commencer. Le problème, c'est pas de trouver la fin de "bidule", mais c'est de trouver le début de "bidule". Tout ce que je sais, c'est qu'avant la valeur entière de bidule, il y a écrit " bidule=" (c'est-à-dire : espace, b, i, d, u, l, e, =).
 
Exemple : si ce qui sort de "commande" ressemble à ceci :

azetycuqsb dfg dfjg dhf
ret
r
er
qsd voiture=45 gfhz rgfhzej
kdghdf hello=45 g bidule=12 hrjkel h difg
of velo=78 udios

j'aimerai obtenir la valeur entière 12. J'arrive à obtenir ce 12 avec le code suivant :

FILE *f = popen("commande", "r" ) ;
char buffer[1000000] ;
fread(buffer, 1, 1000000, f) ;
pclose(f) ;
char *p = strstr(buffer, " chose=" ) ;
p += sizeof " chose=" -1 ;
int bidule ;
sscanf(p, "%i", &bidule) ;


 
Ca marche, mais avouez que ce n'est pas hyper lisible, et que ça prend beaucoup de mémoire pour le buffer. J'aimerai faire plus propre. C'est pour ça, je pense que serait mieux si on pouvait faire ça avec un flux. Mieux compris ?

n°1300143
skelter
Posté le 06-02-2006 à 21:00:55  profilanswer
 

ouai flux et chaine c'est deux conceptes différents, la fonction devrait plutot s'appeler fignore

n°1300435
e-miel
Posté le 07-02-2006 à 13:10:46  profilanswer
 

skelter a écrit :

la fonction devrait plutot s'appeler fignore

Une telle fonction existe-t-elle ?

n°1300439
Elmoricq
Modérateur
Posté le 07-02-2006 à 13:20:19  profilanswer
 

Dans la libC, il n'y a pas grand chose, au fur et à mesure on se constitue souvent une bibliothèque personnelle, d'ailleurs, pour éviter de devoir ré-écrire plusieurs fois les mêmes fonctions.


Message édité par Elmoricq le 07-02-2006 à 13:20:29
n°1300495
Sve@r
Posté le 07-02-2006 à 14:50:13  profilanswer
 

e-miel a écrit :

Facile : j'attends des entiers, et scanf sait très bien s'arrêter là où il faut


Evidemment. Dans ton exemple, tu cherches un nombre et scanf s'arrête tout seul dès qu'il trouve un caractère non numérique (un espace dans ton cas). On en revient au même point. Il faut quand-même que ton flux ait une structure bien définie. Il se trouve que c'est apparemment le cas. En l'ocurrence, je dirais que la structure de ton flux ressemble à "token=nb token=nb token=nb".
 

e-miel a écrit :

C'est pour ça, je pense que serait mieux si on pouvait faire ça avec un flux.


Le gros problème, c'est que si tu lis ton flux par bloc de "n" octets, tu risques d'avoir la fin d'un bloc sur une partie du token.
Exemple: flux=machin=12 bidule=18
Si tu lis ton flux 15 octets par 15 octets, tu auras successivement dans ton buffer

  • <machin=12 bidul>
  • <e=18>

Et tu ne trouveras jamais "bidule=". Le seul algo que je vois serait de lire ton flux octet par octet jusqu'à trouver le premier caractère d'un token. Puis voir si à partir de là on a le token en intégral. Si c'est le cas, tu renvoies ta position dans le fichier. Et si ta fonction doit être indépendante, il faut qu'elle fasse aussi l'ouverture+fermeture du flux. Ca risque d'être lourd...
 

e-miel a écrit :

Mieux compris ?


Ben j'espère que c'est plutôt toi qui a compris que scanf ne fonctionne que parce que ton flux a une structure bien définie qu'il arrive à analyser...


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1300774
e-miel
Posté le 07-02-2006 à 21:49:42  profilanswer
 

Sve@r a écrit :

En l'ocurrence, je dirais que la structure de ton flux ressemble à "token=nb token=nb token=nb".

Pas vraiment, il y a des séquences qui n'ont rien de textuel (même si c'est fait avec des caractères ASCII) et les champs "tocken=nb" sont en plein milieu d'autre chose qui n'a pas la même apparence. Des fois, je dois lire des valeurs entre parenthèses, du type "tocken=(2,54)" alors qu'ailleurs, c'est simplement "tocken=12". Et comme lire un flux caractère par caractère me parait plus coûteux, et plus difficile à comprendre qu'un strstr dans le code source, je vais rester avec mon gros buffer et mon strstr.
 
Merci quand même pour vos propositions.

Message cité 1 fois
Message édité par e-miel le 07-02-2006 à 21:59:06
mood
Publicité
Posté le 07-02-2006 à 21:49:42  profilanswer
 

n°1300778
skelter
Posté le 07-02-2006 à 21:54:13  profilanswer
 

tu peux toujours implémenté ton fignore, et lire cararctere par carctere c'est pas tellement plus couteux, les flux sont bufferisés et meme si c'est un appel de fonction c'est pas comme si c'était un appel systeme.

n°1300847
Sve@r
Posté le 07-02-2006 à 23:12:11  profilanswer
 

e-miel a écrit :

Pas vraiment, il y a des séquences qui n'ont rien de textuel (même si c'est fait avec des caractères ASCII) et les champs "tocken=nb" sont en plein milieu d'autre chose qui n'a pas la même apparence..


Je voulais dire "token=nb blablabla...token=nb blablabla...token=nb...".
 

e-miel a écrit :

Des fois, je dois lire des valeurs entre parenthèses, du type "tocken=(2,54)" alors qu'ailleurs, c'est simplement "tocken=12".


Alors là t'es encore plus mal barré si la structure varie. Je me demande d'ailleurs comment ton "sscanf" peut trouver l'info dans ce cas là...
 

e-miel a écrit :

Et comme lire un flux caractère par caractère me parait plus coûteux, et plus difficile à comprendre qu'un strstr dans le code source, je vais rester avec mon gros buffer et mon strstr.


Mais même là, t'as un souci si ton fichier dépasse les 100ko car ton buffer est limité à 100 000 octets...
 

e-miel a écrit :

Merci quand même pour vos propositions.


 
Pourquoi n'incluerais-tu pas dans ton "popen()" une commande complexe à base de "sed " et/ou "tr" et/ou "awk" pour essayer de tailler ton flux entrant sur un format plus uniforme (style supprimer les parenthèses par exemple) ?

Message cité 1 fois
Message édité par Sve@r le 07-02-2006 à 23:13:22

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1300851
0x90
Posté le 07-02-2006 à 23:17:09  profilanswer
 

pkoi ne pas utiliser flex ?


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1300861
skelter
Posté le 07-02-2006 à 23:22:24  profilanswer
 

ou implementer un fignore, ca fait se fait en 3 lignes et c'est la question de départ

n°1300867
Sve@r
Posté le 07-02-2006 à 23:35:22  profilanswer
 

skelter a écrit :

ou implementer un fignore, ca fait se fait en 3 lignes et c'est la question de départ


Euh... je reste un peu pantois sur l'implémentation en 3 lignes d'une fonction qui traite un tel genre de flux...


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
n°1300871
skelter
Posté le 07-02-2006 à 23:42:21  profilanswer
 

tu boucles sur le resultat de fgetc et tu te sers d'un curseur, c'est franchement pas compliqué ??

n°1300891
0x90
Posté le 08-02-2006 à 00:12:42  profilanswer
 

Code :
  1. int fchercher(FILE *f, const char* str)
  2. {
  3.  int i, count, ret;
  4.  for (count=i=0; str[i]; count++) {
  5.    ret = fgetc(f);
  6.    if (ret == str[i]) i++;
  7.    else if (ret == EOF) return EOF;
  8.  }
  9.  return count;
  10. }


En fait ouais st'assez court à coder (bon j'ai pas fait du propre non plus, quoique déja on à un minimum de retour d'erreur)
 
PS: oui on peut faire plus court c'est vrai :p


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1300919
skelter
Posté le 08-02-2006 à 00:28:22  profilanswer
 

tu devrais faire le test (ret == EOF) avant, ret pourrait valoir EOF mais quand meme satisfaire le test (ret == str[i]) non ?
aussi c'est incomplet, faut remettre i à 0 quand le test (ret == str[i]) n'est plus satisfait et retester sur str[0]
 
j'ai fais ca avec en plus un nombre maximun de caracteres à ignorer (ou 0) et retourne le nombre de caracteres lus
 

Code :
  1. long fignore(FILE * stream, const char * delim, long max)
  2. {
  3. long count = 0;
  4. size_t i = 0;
  5. int c;
  6. while( (!max || count < max) && delim[i] && (c = fgetc(stream)) != EOF )
  7. {
  8.  if( c == delim[i] )
  9.   i++;
  10.  else if( c == delim[0] )
  11.   i = 1;
  12.  else
  13.   i = 0;
  14.  count++;
  15. }
  16. return count;
  17. }

n°1300929
0x90
Posté le 08-02-2006 à 00:43:53  profilanswer
 

skelter a écrit :

tu devrais faire le test (ret == EOF) avant, ret pourrait valoir EOF mais quand meme satisfaire le test (ret == str[i]) non ?


Nan, si c'etait le cas la valeur de retour d'un fgetc serait complètement inutilisable. (sous entendu un string ne peut pas contenir la chaine EOF, ou alors le gars a fait exprès, et c'est tant pis pour sa gueule si le programme pète, un peu comme envoyer un string qui termine pas ... )

skelter a écrit :


aussi c'est incomplet, faut remettre i à 0 quand le test (ret == str[i]) n'est plus satisfait et retester sur str[0]


Oui effectivement, on va dire que c'est la fatigue du soir ...


Message édité par 0x90 le 08-02-2006 à 00:44:28

---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1300938
0x90
Posté le 08-02-2006 à 00:59:48  profilanswer
 

Au passage, mon algo est faux mais le tient aussi, teste le avec :
- un fichier contenant "blahdadadadi"
- l'appel fignore(f,"dadadi",0)
Pour une solution efficace de recherche de chaine dans une chaine sans retour arrière faut utiliser le Knuth-Morris-Pratt si ma mémoire est bonne, et c'est nettement moins trivial [:0x90]


---------------
Me: Django Localization, Yogo Puzzle, Chrome Grapher, C++ Signals, Brainf*ck.
n°1300971
skelter
Posté le 08-02-2006 à 09:28:17  profilanswer
 

bien vu, j'avais pas du tout penser à ca

n°1301610
skelter
Posté le 08-02-2006 à 20:48:14  profilanswer
 

en fait ca se fait assez simplement (c'est meme encore plus simple) avec memmove
 

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. long fignore(FILE * stream, const char * delim, long max)
  5. {
  6. long count = 0;
  7. int c;
  8. size_t len;
  9. char * s;
  10. len = strlen(delim);
  11. if( ! (s = malloc(len + 1)) )
  12.  return 0;
  13. while( (!max || count++ < max) && (c = fgetc(stream)) != EOF )
  14. {
  15.  memmove(s, s + 1, len);
  16.  s[len - 1] = c;
  17.  s[len] = '\0';
  18.  if( ! strcmp(delim, s) )
  19.   break;
  20. }
  21. free(s);
  22. return count;
  23. }


 
je sais pas si c'est efficace mais c'est simple et ca marche

n°1301709
e-miel
Posté le 08-02-2006 à 22:38:58  profilanswer
 

Sve@r a écrit :

Alors là t'es encore plus mal barré si la structure varie. Je me demande d'ailleurs comment ton "sscanf" peut trouver l'info dans ce cas là...

Si la chaîne recherchée est "bidule=(" puis "," il n'y a aucun problème. Faut bricoler, mais ça marche.

Sve@r a écrit :

Mais même là, t'as un souci si ton fichier dépasse les 100ko car ton buffer est limité à 100 000 octets...

J'aurai plutôt dit une limite à 8 Mo (taille de la pile)... en supposant que les fonctions déjà empilées (fonctions appelantes) ne prennent pas beaucoup de place dans la pile (par chance, c'est le cas).

Sve@r a écrit :

Pourquoi n'incluerais-tu pas dans ton "popen()" une commande complexe à base de "sed " et/ou "tr" et/ou "awk" pour essayer de tailler ton flux entrant sur un format plus uniforme (style supprimer les parenthèses par exemple) ?

Les noms et l'aspect des champs n'est pas si régulier que ça, je me retrouverai avec un sed compliqué. Sinon, le awk c'est comme du C interprété, donc aurant rester au C.
 
Sinon, pour toutes vos méthodes, je ne dis pas qu'elles ne marchent pas, mais ce que je cherche c'est le code source le plus simple possible... donc, on va en rester là. Merci quand même. ;)


Message édité par e-miel le 08-02-2006 à 22:41:18
mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  Existe-t-il une fonction qui cherche dans un flux ?

 

Sujets relatifs
Rediriger en fonction de la date?passer un parametre a une fonction
fonction qui retourne code HTML d'un char spécial[résolu] Fonction mail, je ne reçois rien...
suite d'action dans une fonctionCherche une fonction pour 'aspirer' un fichier HTTP (une page, par ex)
Recherche d'une fonction qui ajoute les slashs.problème avec la fonction onBlur
fonction Timer vide, problème ??? 
Plus de sujets relatifs à : Existe-t-il une fonction qui cherche dans un flux ?


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR