2017-12-16 7 views
0

Ich versuche, eine callrate calculater zu machen, wo der Eingang wird wie folgt erfolgen: hh: mmParse String in ganzen Zahlen mit Trennzeichen C++

Danach i mit nur diese Zeichenfolge in zwei Ints analysieren wollen ‚:‘ als Trennzeichen. Diese Lösung, die ich hier gefunden habe, scheint nur mit dem Raum zu arbeiten, aber ich möchte, dass das Trennzeichen Doppelpunkte und kein Leerzeichen ist. Gibt es überhaupt einen möglichen Weg dazu?

#include <iomanip> 
#include <iostream> 
#include <string> 
#include <sstream> 

using namespace std; 

int main() { 

    string input; 
    getline(cin, input); 
    istringstream is(input); 
    int hours, minutes; 

    is >> hours>> minutes; 

    cout << timmar << endl; 
    cout << minuter << endl; 
} 

Antwort

1

Lesen Sie das Trennzeichen in eine andere Variable.

char colon; 

is >> hours >> colon >> minutes; 
if (colon != ':') { 
    cout << "Incorrect delimiter: " << colon << '\n'; 
} 
+0

Solch eine einfache Lösung! Beeindruckend. Danke :) – Thesar

+0

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. –

0

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"; 
    } 
}