2009-12-23 4 views
5

J'ai déjà du code pour lire un fichier texte en utilisant fscanf(), et maintenant j'ai besoin de le modifier pour que les champs qui étaient auparavant sans espace doivent permettre les espaces. Le fichier texte est essentiellement sous la forme de:Can fscanf() lit-il des espaces?

Titre: DONNÉES
Titre: DATA
etc ...

qui est essentiellement parsé en utilisant fgets(inputLine, 512, inputFile); sscanf(inputLine, "%*s %s", &data);, la lecture des champs de données et en ignorant les titres, mais maintenant certains des champs de données doivent autoriser des espaces. J'ai encore besoin d'ignorer le titre et l'espace immédiatement après, mais ensuite lire dans le reste de la ligne, y compris les espaces.

Est-il possible de le faire avec la fonction sscanf()? Sinon, quel est le plus petit changement que je peux apporter au code pour gérer correctement les espaces? MISE À JOUR: J'ai édité la question pour remplacer fscanf() par fgets() + sscanf(), ce que mon code utilise réellement. Je ne pensais pas vraiment que c'était pertinent quand j'ai écrit la question, c'est pourquoi je l'ai simplifié à fscanf().

+0

Si vous l'analysiez avec 'scanf', vous pourriez aussi analyser quelque chose comme' title: DATA title: DATA' (c'est-à-dire tous sur une ligne). Si vous voulez autoriser les espaces dans les valeurs, quel sera le terminateur? Si newline, alors il semble que votre code original était un peu trop laxiste ... –

+0

Aussi, comment décidez-vous de la taille du buffer 'str', et comment vous assurez-vous qu'il ne déborde pas? –

+0

oui, quand les données peuvent avoir des espaces, la nouvelle ligne sera utilisée comme terminaison –

Répondre

11

Si vous ne pouvez pas utiliser fgets() utiliser les indicateurs de conversion %[ (avec l'option "exclure"):

char buf[100]; 
fscanf(stdin, "%*s %99[^\n]", buf); 
printf("value read: [%s]\n", buf); 

Mais fgets() est bien meilleur.


Edit: version avec fgets() + sscanf()

char buf[100], title[100]; 
fgets(buf, sizeof buf, stdin); /* expect string like "title: TITLE WITH SPACES" */ 
sscanf(buf, "%*s %99[^\n]", title); 
+3

Dans ce cas particulier, comment «fgets» est-il «bien meilleur»? –

+1

Eh bien ... les exigences ne cessent de changer (d'abord il n'y avait pas d'espace dans la chaîne). Ce n'est pas mieux pour ce cas particulier, mais il est préférable d'utiliser 'fgets()' maintenant, en antécipitation pour le prochain changement d'exigences :) – pmg

+0

J'ai mis à jour la question pour montrer que j'utilise effectivement fgets() pour lire la ligne, puis sscanf() pour l'analyser, mais est-il un meilleur moyen d'analyser la ligne après fgets()? –

3

Je vous suggère fortement d'arrêter d'utiliser fscanf() et de commencer à utiliser fgets() (qui lit toute une ligne), puis d'analyser la ligne qui a été lue.

Ceci vous laissera beaucoup plus de liberté pour l'analyse d'une entrée non formatée.

+0

J'ai mis à jour la question pour montrer que j'utilise réellement fgets(), mais je ne comprends pas ce que cela va aider. Je dois encore analyser la ligne une fois que je l'ai lue. –

+1

Une fois que vous avez la chaîne entière, marchez-la vous-même plutôt que d'utiliser sscanf. –

+0

Oui, faites-le avec des pointeurs, ou mieux utilisez des expressions régulières. Si vous utilisiez C++, j'aurais suggéré boost; Je ne connais pas de bonnes bibliothèques C, mais il doit y en avoir. J'ai entendu POSIX les soutenir. –

2

La chose la plus simple serait de délivrer un

fscanf("%*s"); 

pour rejeter la première partie, puis il suffit d'appeler les fgets:

fgets(str, stringSize, filePtr); 
3

Si vous insistez sur l'utilisation scanf, et en supposant que vous voulez newline en tant que terminaison, vous pouvez le faire:

scanf("%*s %[^\n]", str); 

Notez, cependant, que ce qui précède, utilisé exactement comme écrit, est une mauvaise idée parce que Il n'y a rien à se prémunir contre str survolé (comme scanf ne sait pas sa taille). Vous pouvez, bien sûr, définir une taille maximale prédéfinie, et spécifier cela, mais alors votre programme peut ne pas fonctionner correctement sur une entrée valide.Si la taille de la ligne, définie par le format d'entrée, n'est pas limitée, alors votre seule option pratique est d'utiliser fgetc pour lire les données char by char, en réallouant périodiquement le tampon au fur et à mesure. Si vous le faites, modifiez-le pour supprimer tous les caractères lus jusqu'à ce que le premier espace soit assez trivial.

2

Un spécificateur %s dans fscanf ignore tout espace sur l'entrée, puis lit une chaîne de caractères non espaces jusqu'au caractère espace blanc suivant.

Si vous voulez lire un retour à la ligne, vous pouvez utiliser %[^\n] comme spécificateur. De plus, un '' dans la chaîne de format sautera des espaces sur l'entrée. Donc, si vous utilisez

fscanf("%*s %[^\n]", &str); 

il lit la première chose sur la ligne jusqu'à la première des espaces (« title: » dans votre cas), et le jeter, puis lira les caractères blancs et les jeter, puis lira tous les caractères jusqu'à une nouvelle ligne dans str, ce qui ressemble à ce que vous voulez.

Faites attention que str ne déborde pas - vous pouvez utiliser

fscanf("%*s %100[^\n]", &str) 

pour limiter la longueur maximale de la chaîne que vous allez lire (100 caractères, sans compter un NUL se terminant ici).

+0

Je sais que c'est un court exemple, mais devez-vous utiliser l'adresse de str? Je pense que cela fonctionnerait aussi. 'fscanf ("% * s% [^ \ n] ", str);' – cokedude

1

Vous vous heurtez aux limites de ce que la famille *scanf est bon pour. Avec des modifications minimes, vous pouvez essayer d'utiliser les modules de balayage de chaînes de C Interfaces and Implementations de Dave Hanson. Ce matériel est une adaptation du langage de programmation Icon, un langage de traitement de texte extrêmement simple et puissant sur lequel Hanson et d'autres ont travaillé en Arizona. Le départ de sscanf ne sera pas trop sévère, et il est plus simple, plus facile à utiliser, et plus puissant que les expressions régulières. Le seul inconvénient est que le code est un peu difficile à suivre sans le livre — mais si vous faites beaucoup de programmation en C, le livre vaut la peine d'avoir.