2009-08-24 7 views
27

Ich weiß, dass diese Frage in der Vergangenheit schon mehrmals gestellt wurde, aber ich werde trotzdem weitermachen.Konvertieren String mit mehreren Zahlen in ganze Zahlen

Ich habe ein Programm, das eine Reihe von Zahlen von Tastatureingabe erhalten wird. Die Zahlen werden immer in der Form "66 33 9" sein. Im Grunde ist jede Zahl durch ein Leerzeichen getrennt und die Benutzereingabe enthält immer eine andere Anzahl von Zahlen.

Ich bin mir bewusst, dass die Verwendung von 'sscanf' funktionieren würde, wenn die Anzahl der Zahlen in jeder vom Benutzer eingegebenen Zeichenfolge konstant ist, aber das ist nicht der Fall für mich. Da ich neu in C++ bin, würde ich lieber mit String-Variablen als mit Chars-Arrays arbeiten.

+6

IMO im Allgemeinen bevorzugen 'std :: stri ng über rohe Zeichenpuffer ist kein Zeichen von "Neuling", sondern eher von Reife. – sbi

Antwort

29

Ich nehme an, Sie möchten eine ganze Zeile lesen und diese als Eingabe analysieren. Also, packen zuerst die Zeile:

std::string input; 
std::getline(std::cin, input); 

Nun, da setzte sich in eine stringstream:

std::stringstream stream(input); 

und analysieren

while(1) { 
    int n; 
    stream >> n; 
    if(!stream) 
     break; 
    std::cout << "Found integer: " << n << "\n"; 
} 

Denken Sie daran, umfassen

#include <string> 
#include <sstream> 
+18

Sie meinen parse: 'int n; while (Strom >> n) {std :: cout << "Gefundene Ganzzahl:" << n << "\ n";} '? Viel sauberer –

1

Here is wie Sie Ihre Zeichenfolge in Zeichenfolgen entlang der Leerzeichen aufteilen. Dann können Sie sie einzeln bearbeiten.

0

Versuchen Sie strtoken, um die Zeichenfolge zuerst zu trennen, dann werden Sie mit jeder Zeichenfolge befassen.

2
#include <string> 
#include <vector> 
#include <sstream> 
#include <iostream> 
using namespace std; 

int ReadNumbers(const string & s, vector <int> & v) { 
    istringstream is(s); 
    int n; 
    while(is >> n) { 
     v.push_back(n); 
    } 
    return v.size(); 
} 

int main() { 
    string s; 
    vector <int> v; 
    getline(cin, s); 
    ReadNumbers(s, v); 
    for (int i = 0; i < v.size(); i++) { 
     cout << "number is " << v[i] << endl; 
    } 
} 
8
#include <string> 
#include <vector> 
#include <iterator> 
#include <sstream> 
#include <iostream> 

int main() { 
    std::string input; 
    while (std::getline(std::cin, input)) 
    { 
     std::vector<int> inputs; 
     std::istringstream in(input); 
     std::copy(std::istream_iterator<int>(in), std::istream_iterator<int>(), 
     std::back_inserter(inputs)); 

     // Log process: 
     std::cout << "Read " << inputs.size() << " integers from string '" 
     << input << "'" << std::endl; 
     std::cout << "\tvalues: "; 
     std::copy(inputs.begin(), inputs.end(), 
     std::ostream_iterator<int>(std::cout, " ")); 
     std::cout << std::endl; 
    } 
} 
+3

+1, sobald Sie 1000 "Std ::" s mit einem einzigen ersetzen "using Namespace std;" und erwähne die Header, die du brauchst. –

+5

+1, solange Sie die Präfixe 'std ::' beibehalten. Ihre Lesbarkeit ist subjektiv (ich bin daran gewöhnt, finde es viel besser zu lesen), aber die verbesserte Klarheit durch voll qualifizierte Namen ist objektiv. – sbi

+0

+1 nach dem Ersetzen mit 'using namespace'. Dann können Sie die Implementierung durch eine andere ersetzen und müssen nicht mit Namensraumänderungen umgehen. – nothrow

1
// get string 
std::string input_str; 
std::getline(std::cin, input_str); 

// convert to a stream 
std::stringstream in(input_str); 

// convert to vector of ints 
std::vector<int> ints; 
copy(std::istream_iterator<int, char>(in), std::istream_iterator<int, char>(), back_inserter(ints)); 
1

generische Lösung für Werte ohne Vorzeichen (mit Präfix zu tun '-' nimmt eine zusätzliche bool):

template<typename InIter, typename OutIter> 
void ConvertNumbers(InIter begin, InIter end, OutIter out) 
{ 
    typename OutIter::value_type accum = 0; 
    for(; begin != end; ++begin) 
    { 
     typename InIter::value_type c = *begin; 
     if (c==' ') { 
      *out++ = accum; accum = 0; break; 
     } else if (c>='0' && c <='9') { 
      accum *= 10; accum += c-'0'; 
     } 
    } 
    *out++ = accum; 
     // Dealing with the last number is slightly complicated because it 
     // could be considered wrong for "1 2 " (produces 1 2 0) but that's similar 
     // to "1 2" which produces 1 0 2. For either case, determine if that worries 
     // you. If so: Add an extra bool for state, which is set by the first digit, 
     // reset by space, and tested before doing *out++=accum. 
} 
+0

+1 da beantworten Sie die Frage wie angegeben ("Ganzzahlen"), aber ich denke, das ist eigentlich ein Schritt in die weniger generische Richtung in mancher Hinsicht, wie es wird funktioniert natürlich nur für Ganzzahlen und nicht für andere Typen (IOW: die "genericity" von "typenname OutIter :: value_type accym = 0;" ist überzeichnet). Wie würden Sie zum Beispiel mit Fließkommazahlen umgehen? Wenn Sie einen anderen Mini-Lexer schreiben möchten, vergessen Sie nicht, mit wissenschaftlicher Notation und Inf, NaN usw. umzugehen. –

+0

Nun, es akzeptiert 'short []', 'std :: vector ' und 'std :: list 'oder tatsächlich jeder andere Integraltyp (einschließlich implementierungsdefinierter Typen). Plain 0 wird in alle konvertiert. Der Grund, warum ich den Werttyp dort verwendet habe, ist, dass ich nicht zufällig ein "int" überlaufen lasse, wenn der Benutzer als "__int128 []" und eine Zeichenfolge mit so großen Zahlen übergibt. – MSalters

+0

Die Verwendung von value_type für accum ist absolut der richtige Weg, aber ich denke, ich sehe nicht, warum du nicht einfach einen istringstream anstelle deines eigenen handgefertigten Lexers verwenden könntest. Dann könnten Sie mit jedem Typ arbeiten, der vom Operator <<() verstanden wird (d. H. Verbesserte "typisierte" Generizität), ohne die "iteratormäßige" Generizität Ihrer aktuellen Lösung zu opfern. Ich vermute auch, dass es wahrscheinlicher ist, mit breiten Zeichen, Schauplätzen usw. zu arbeiten. –

18

Die C++ String Toolkit Library (Strtk) hat die folgende Lösung für Ihr Problem:

#include <iostream> 
#include <string> 
#include <deque> 
#include <algorithm> 
#include <iterator> 

#include "strtk.hpp" 

int main() 
{ 
    std::string s = "1 23 456 7890"; 

    std::deque<int> int_list; 
    strtk::parse(s," ",int_list); 

    std::copy(int_list.begin(), 
      int_list.end(), 
      std::ostream_iterator<int>(std::cout,"\t")); 

    return 0; 
} 

Weitere Beispiele finden Sie Here