2009-08-24 23 views
27

Me doy cuenta de que esta pregunta puede haber sido formulada varias veces en el pasado, pero voy a continuar independientemente.Convertir cadena que contiene varios números en números enteros

Tengo un programa que va a obtener una cadena de números de la entrada del teclado. Los números siempre estarán en el formato "66 33 9". Esencialmente, cada número se separa con un espacio, y la entrada del usuario siempre contendrá una cantidad diferente de números.

Soy consciente de que el uso de 'sscanf' funcionaría si la cantidad de números en cada cadena ingresada por el usuario fuese constante, pero este no es el caso para mí. Además, como soy nuevo en C++, preferiría tratar con variables 'de cadena' en lugar de matrices de caracteres.

+6

IMO generalmente prefiriendo 'std :: stri ng' sobre los almacenamientos intermedios de caracteres sin procesar no es un signo de "novedad", sino más bien de madurez. – sbi

Respuesta

29

Supongo que quiere leer una línea completa y analizarla como entrada. Así, en primer coger la línea:

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

Ahora poner esto en un stringstream:

std::stringstream stream(input); 

y analiza

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

recuerde incluir

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

Quiere decir analizar: 'int n; while (stream >> n) {std :: cout << "Número entero encontrado:" << n << "\ n";} '? Mucho más limpio –

1

Here is cómo dividir la cadena en cadenas a lo largo de los espacios. Luego puede procesarlos uno a uno.

0

Pruebe strtoken para separar primero la cuerda, luego se ocupará de cada cuerda.

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 una vez que reemplaza 1000 "std ::" s con un solo "using namespace std;" y menciona los encabezados que necesitas. –

+5

+1 siempre que conserve los prefijos 'std ::'. Su legibilidad es subjetiva (yo, acostumbrado a ellos, creo que es mucho mejor para leer), pero la claridad mejorada a través de nombres completamente calificados es objetiva. – sbi

+0

+1 después de reemplazar con 'using namespace'. Luego puede reemplazar la implementación con otra y no necesita lidiar con el cambio del espacio de nombres. – 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

solución genérica para los valores sin signo (que trata con el prefijo '-' toma un bool extra):

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 ya que responde la pregunta tal como se establece ("enteros"), pero creo que esto es en realidad un paso en la dirección menos genérica en algunos aspectos, ya que claramente solo funciona para enteros y no para otros tipos (IOW: la "genericidad" de "typename OutIter :: value_type accum = 0;" es exagerada). ¿Cómo manejaría los números de coma flotante, por ejemplo? Si desea escribir otro mini-lexer, no olvide manejar la notación científica e Inf, NaN etc. –

+0

Bueno, aceptará 'short []', 'std :: vector ' y 'std :: list 'o de hecho, cualquier otro tipo integral (incluidos los tipos definidos por la implementación). Plain 0 se convertirá a todos esos. La razón por la que usé el tipo de valor es para no desbordar accidentalmente un 'int' cuando el usuario pasa como' __int128 [] 'y una cadena con números tan grandes. – MSalters

+0

El uso de value_type para accum es absolutamente el camino correcto, pero supongo que no veo por qué no podría simplemente usar un istringstream en lugar de su propio lexer artesanal. Entonces podría trabajar con cualquier tipo entendido por el operador <<() (es decir, una genérica de tipo "typewise" mejorada) sin sacrificar la genericidad "iteratorwise" de su solución actual. También sospecho que es más probable que funcione con caracteres anchos, locales, etc. –

18

El C++ String Toolkit Library (Strtk) tiene la siguiente solución a su problema:

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

Más ejemplos se pueden encontrar Here

Cuestiones relacionadas