Statt ein Standardtrennzeichen von erwarten würde ich einen benutzerdefinierten Manipulator verwendet speziell mit dem Trennzeichen zu behandeln:
std::istream& colon(std::istream& in) {
if (in.peek() != ':' || std::isspace(in.ignore().peek())) {
in.setstate(std::ios_base::failbit);
}
return in;
}
// ...
int hours, minutes;
if (in >> hours >> colon >> minutes) {
// process the input
}
Mit diesem Manipulator Plätze in der Nähe des Dickdarms vermeiden, als gültig betrachtet: die Der normale Eingabevorgang beginnt mit dem Überspringen von Leerzeichen. Das einfache Lesen des Begrenzers in eine Variable würde Leerzeichen vor dem Begrenzer zulassen und außerdem jedes Nicht-Leerzeichen als Trennzeichen zulassen. Das Lesen direkt nach dem Trennzeichen würde wiederum Leerzeichen nach dem Trennzeichen zulassen. Mit dem obigen Manipulator colon
werden beide Fälle zu einem Fehler. ... und natürlich Sie immer müssen nach lesen und vor mit den Ergebnissen überprüfen, ob die Eingabe erfolgreich war.
Eine ganz andere Herangehensweise an das gleiche Problem ist der Strom der Notation von Leerzeichen neu zu definieren. Die Idee hier ist, die std::locale
des Stroms und a std::locale
zu nutzen, die den gewünschten Separator, z. B. :
als den einzigen "Leerraum" betrachtet. Unten ist ein vollständiges Beispiel, das diese Idee demonstriert. Es verwendet eine separate std::istream
mit einer benutzerdefinierten std::locale
, um zu vermeiden, wie std::cin
funktioniert. Es verwendet jedoch immer noch std::cin
Strompuffer, d. H. Es liest aus derselben Quelle wie std::cin
.
#include <algorithm>
#include <locale>
struct myctype_base {
std::ctype<char>::mask table[std::ctype<char>::table_size];
myctype_base(unsigned char c) {
table[c] |= std::ctype_base::space;
}
};
struct myctype
: private myctype_base
, std::ctype<char> {
public:
myctype(char delimiter)
: myctype_base(delimiter)
, std::ctype<char>(myctype_base::table) {
}
};
int main() {
std::locale loc(std::locale(), new myctype(':'));
std::istream in(std::cin.rdbuf());
in.imbue(loc);
int hours, minutes;
if (in >> hours >> minutes) {
std::cout << "read hours=" << hours << " minutes=" << minutes << "\n";
}
else {
std::cout << "failed to read input\n";
}
}
Solch eine einfache Lösung! Beeindruckend. Danke :) – Thesar
Natürlich funktioniert es nicht wirklich für interessante Eingaben. Zum Beispiel sollte "01: 02" wahrscheinlich nicht kompilieren. Das Problem kann mit einem 'Doppelpunkt'-Manipulator behoben werden:' std :: istream & colon (std :: isotream & in) {if (in.peek()! = ':') In.setstate (std :: ios_base :: failbit); sonst in.ignore(); zurückkehren in; } '. Sie würden diesen Manipulator wie Barmars "char" verwenden, aber es erzeugt einen Fehler, wenn der Doppelpunkt nicht direkt den Stunden folgt. Es würden jedoch immer noch Leerzeichen vor den Minuten angezeigt. Also, du würdest wirklich 'if (Stunden >> Doppelpunkt >> Std :: Noskipws >> Minuten >> Std :: Skipws) {...} verwenden. –