Je vais vous montrer ce que je pense que c'est la façon correcte de faire ça en C++. Tout d'abord définir une classe pour représenter votre première ligne et pour faire son IO:
struct FirstLine
{
double x, y, z;
friend std::istream & operator>>(std::istream & is, FirstLine & data)
{
std::string line, ignore;
std::getline(is, line);
std::istringstream iss(line);
iss >> ignore >> data.x >> data.y >> data.z;
assert(ignore == "P" && iss);
return is;
}
friend std::ostream & operator<<(std::ostream & os, FirstLine const & data)
{
return os << "P " << data.x << " " << data.y << " " << data.z;
}
};
J'ai ajouté une erreur de base de vérification avec assert, vous voudrez probablement quelque chose de plus solide dans votre programme final.
maintenant une classe pour les lignes moyennes:
struct MiddleLine
{
double x, y;
friend std::istream & operator>>(std::istream & is, MiddleLine & data)
{
std::string line;
std::getline(is, line);
if(line == "T")
is.clear(std::ios::failbit);
else
{
int n = sscanf(line.c_str(), "%lf %lf", &data.x, &data.y);
assert(n == 2);
}
return is;
}
friend std::ostream & operator<<(std::ostream & os, MiddleLine const & data)
{
return os << data.x << " " << data.y;
}
};
Quand nous arrivons à la fin de la section où les lignes moyennes sont nous sommes censés rencontrer un « T ». Dans ce cas, nous élevons le bit d'échec du flux, ce qui indiquera au client qu'il n'y a plus de lignes intermédiaires à lire.
Enfin une classe pour les dernières lignes:
struct LastLine
{
std::string identifier; // r, s or t
std::vector<double> values;
friend std::istream & operator>>(std::istream & is, LastLine & data)
{
std::string line;
std::getline(is, line);
std::istringstream iss(line);
iss >> data.identifier;
assert(data.identifier == "r" || data.identifier == "s"
|| data.identifier == "t");
std::copy(std::istream_iterator<double>(iss),
std::istream_iterator<double>(), std::back_inserter(data.values));
return is;
}
friend std::ostream & operator<<(std::ostream & os, LastLine const & data)
{
os << data.identifier << " ";
std::copy(data.values.begin(), data.values.end(),
std::ostream_iterator<double>(os, " "));
return os;
}
};
dernières lignes sont plus compliquées becase nous ne savons pas combien de valeurs sont dans chaque, donc nous lisons tout autant que nous le pouvons.
C'était la partie délicate. Maintenant, notre fonction principale sera simplement lire une première ligne, puis un nombre inconnu de lignes intermédiaires, et enfin un nombre inconnu de dernières lignes:
int main()
{
std::string const data = "P 0.5 0.6 0.3\n
"30 300\n"
"80 150\n"
"160 400\n"
"200 150\n"
"250 300\n"
"T\n"
"r 45 0 0\n"
"s 0.5 1.5 0 0\n"
"t 200 –150";
std::istringstream iss(data);
FirstLine first_line;
iss >> first_line;
std::vector<MiddleLine> middle_lines;
std::copy(std::istream_iterator<MiddleLine>(iss),
std::istream_iterator<MiddleLine>(),
std::back_inserter(middle_lines));
iss.clear();
std::vector<LastLine> last_lines;
std::copy(std::istream_iterator<LastLine>(iss),
std::istream_iterator<LastLine>(),
std::back_inserter(last_lines));
assert(iss.eof());
std::cout << first_line << "\n";
std::copy(middle_lines.begin(), middle_lines.end(),
std::ostream_iterator<MiddleLine>(std::cout, "\n"));
std::copy(last_lines.begin(), last_lines.end(),
std::ostream_iterator<LastLine>(std::cout, "\n"));
return 0;
}
Ceci est la sortie que vous obtiendrez ::
P 0.5 0.6 0.3
30 300
80 150
160 400
200 150
250 300
r 45 0 0
s 45 0 0 0.5 1.5 0 0
t 45 0 0 0.5 1.5 0 0 200
J'ai utilisé une chaîne comme source de mes données mais vous voudrez probablement lire un fichier.
Et c'est tout, vous pouvez voir que je n'ai pas écrit une seule boucle.
Here's the code dans le codepad.
BTW votre question m'a fait poser celui-ci: http://stackoverflow.com/questions/2309604 "Est-ce que quelqu'un utilise réellement les opérateurs d'extraction de flux?" – Dan