OVH Cloud OVH Cloud

[newbie]fin de ligne

7 réponses
Avatar
Antoine ALBERT
Bonjour,
J'ai une série de données en lignes, séparées par des virgules, dans un
fichier texte. J'arrive à saisir mes données (fscanf("%lf,",&variable);)
mais je ne sais pas comment arreter mon acquisition (ie quand je suis au
bout de la ligne). Mon nombre de données n'est pas fixe!
J'aimerais éviter l'acquisition par une chaine, qui nécessiterait la
déclaration d'un tableau de caractères trop grand.
Merci d'avance pour votre aide et vos suggestions.

Antoine

7 réponses

Avatar
Michaël Monerau
Antoine ALBERT wrote:
Bonjour,
J'ai une série de données en lignes, séparées par des virgules, dans
un fichier texte. J'arrive à saisir mes données
(fscanf("%lf,",&variable);) mais je ne sais pas comment arreter mon
acquisition (ie quand je suis au bout de la ligne). Mon nombre de
données n'est pas fixe!
J'aimerais éviter l'acquisition par une chaine, qui nécessiterait la
déclaration d'un tableau de caractères trop grand.


Aïe... Ce que tu proposes là est du C (alors : news:fr.comp.lang.c). Sinon,
si tu veux vraiment faire du C++, on utilise les flux plus simplement :

int i;
vector<int> MesInts;

while (cin >> i)
MesInts.push_back (i);

C'est plus `safe', et plus pratique aussi.

Ca s'arrêtera tout seul au bout de la ligne. Il y a d'autres moyens avec un
back_inserter mais je ne connais pas bien ce côté-là, mais je préfère te
donner des pistes que je connais ;-)
--
<=- Michaël "Cortex" Monerau -=>

Avatar
Jonathan Mcdougall
int i;
vector<int> MesInts;

while (cin >> i)
MesInts.push_back (i);

Ca s'arrêtera tout seul au bout de la ligne. Il y a d'autres moyens avec
un

back_inserter mais je ne connais pas bien ce côté-là, mais je préfère te
donner des pistes que je connais ;-)


std::copy( std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(MesInts));

tout simplement :)


Jonathan

Avatar
Michaël Monerau
Jonathan Mcdougall wrote:
std::copy( std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(MesInts));

tout simplement :)


eheh ;-)
--
<=- Michaël "Cortex" Monerau -=>

Avatar
kanze
"Michaël Monerau" wrote in message
news:<OMieb.201192$...
Antoine ALBERT wrote:

J'ai une série de données en lignes, séparées par des virgules, dans
un fichier texte. J'arrive à saisir mes données
(fscanf("%lf,",&variable);) mais je ne sais pas comment arreter mon
acquisition (ie quand je suis au bout de la ligne). Mon nombre de
données n'est pas fixe! J'aimerais éviter l'acquisition par une
chaine, qui nécessiterait la déclaration d'un tableau de caractères
trop grand.


Aïe... Ce que tu proposes là est du C (alors : news:fr.comp.lang.c).
Sinon, si tu veux vraiment faire du C++, on utilise les flux plus
simplement :

int i;
vector<int> MesInts;

while (cin >> i)
MesInts.push_back (i);

C'est plus `safe', et plus pratique aussi.

Ca s'arrêtera tout seul au bout de la ligne.


Non, ça ne s'arrêtera pas au bout de la ligne. Ça ne s'arrêtera qu'à la
fin du fichier.

La façon habituelle de traiter une seule ligne, c'est :

std::string ligne ;
if ( ! std::getline( std::cin, ligne ) ) {
// Erreur...
} else {
std::istringstream s( ligne ) ;
// ...
Parser la ligne...
}

Dans son cas, c'est encore plus complexe, parce que le séparateur, c'est
une virgule, et non des espaces. Alors, il n'y a pas de support direct ;
il faut vraiment parser. Quelque chose du genre :

bool
getValue( std::istream& s, std::vector< double >& v )
{
double tmp ;
s >> tmp ;
if ( s ) {
v.push_back( tmp ) ;
}
return s ;
}

bool
checkSeparator( s )
{
char ch ;
return s >> ch && ch == ',' ;
}

std::vector< double > result ;
std::string ligne ;
if ( std::getline( std::cin, ligne ) ) {
std::istringstream s( ligne ) ;
while ( getValue( s, result ) && checkSeparator( s ) ) {
}
}

Même là, il manque bien de traitement des erreurs.

Il y a d'autres moyens avec un back_inserter mais je ne connais pas
bien ce côté-là, mais je préfère te donner des pistes que je connais
;-)


Je ne vois pas l'avantage que tu donnera un back_iterator ici.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16


Avatar
kanze
"Jonathan Mcdougall" wrote in message
news:<%Yjeb.68765$...

int i;
vector<int> MesInts;

while (cin >> i)
MesInts.push_back (i);

Ca s'arrêtera tout seul au bout de la ligne. Il y a d'autres moyens
avec un back_inserter mais je ne connais pas bien ce côté-là, mais
je préfère te donner des pistes que je connais ;-)


std::copy( std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(MesInts));

tout simplement :)


Ce qui correspond bien à son code, mais qui ne résoud pas le problème
initial non plus.

Le problème initial avait deux aspects importants à tenir en
considération.

D'abord, il ne devait lire qu'une seule ligne. La solution la plus
facile, c'est d'utiliser getline pour lire la ligne entièrement d'un
coup, puis l'utiliser la ligne pour initialiser un istringstream d'où on
lit les valeurs. Si pour une raison quelconque, one ne peut pas adopter
cette solution (chose qui m'étonnerait), il faudrait pratiquement
scanner la source caractère par caractère, au moyen de istream::get,
parce que quand on lit avec les <<, le 'n' est considéré comme un
espace blanc, et on le saute.

Le deuxième problème, c'est que les valeurs sont séparées par des
virgules, et non simplement des espaces. Et les solutions proposées
ci-dessus s'arrêtera avec une erreur à la première virgule. Il faut donc
lire les caractères entre les valeurs, et vérifier qu'il y a une
virgule.

En fait, ça doit donner quelque chose du genre :

std::istream&
sautVirgule( std::istream& s )
{
char tmp ;
s >> tmp ;
if ( s && tmp != ',' ) {
s.setstate( std::ios::failbit ) ;
}
return s ;
}

std::istream&
lireLigneDeDoubles(
std::istream& source,
std::vector< double >& dest )
{
std::string ligne ;
if ( std::getline( source, ligne ) ) {
std::istringstream s( ligne ) ;
double tmp ;
s >> tmp ;
while ( s ) {
dest.push_back( tmp ) ;
sautVirgule( s ) ;
}
if ( ! s.eof() ) {
dest.setstate( std::ios::failbit ) ;
}
}
return source ;
}

Après appel de la fonction, il faudrait évidemment tester l'état du
flux. Comme d'habitude.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16


Avatar
Michel Michaud
Dans news:,
Dans son cas, c'est encore plus complexe, parce que le séparateur,
c'est une virgule, et non des espaces. Alors, il n'y a pas de
support direct ; il faut vraiment parser. Quelque chose du genre :


Pourquoi pas getline(flux, valeur, ',') ?

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/

Avatar
kanze
"Michel Michaud" wrote in message
news:<dsKeb.5106$...
Dans news:,
Dans son cas, c'est encore plus complexe, parce que le séparateur,
c'est une virgule, et non des espaces. Alors, il n'y a pas de
support direct ; il faut vraiment parser. Quelque chose du genre :


Pourquoi pas getline(flux, valeur, ',') ?


Parce que le nom de la fonction ne dit pas ce qu'il fait:-).

Sérieusement, j'ai supposé que les virgules étaient des séparateurs, et
non des terminateurs. C'est donc que la dernière valeur ne serait pas
suivie d'une virgule. Et qu'on ne sait que c'est la dernière valeur
qu'après l'avoir lu et avoir vu un 'n' à la place de la virgule.

C'est un problème assez fréquent dont on n'a pas vraiment une bonne
solution tout faite dans la bibliothèque standard. On pourrait, par
exemple, utiliser mes FieldArray pour la résoudre, mais au moins de les
avoir sous la main, et de les connaître aussi bien qu'on connaît la
bibliothèque standard, je ne crois pas que ça donnerait une solution
plus simple que celui que j'ai posté. (En revanche, je verrais bien un
manipulateur qui faisait à peu près ce que j'ai fait dans ma fonction
sautVirgule.)

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16