Cuando yo uso getline, me gustaría entrada de un montón de cadenas de caracteres o números, pero solo quiero que el bucle while de la salida de la «palabra» si no es un número.
Entonces, ¿hay alguna forma de comprobar si la «palabra» es un número o no? Sé que podría utilizar atoi() para
C-cadenas, pero ¿y para las cadenas de la clase string?

int main () {
  stringstream ss (stringstream::in | stringstream::out);
  string word;
  string str;
  getline(cin,str);
  ss<<str;
  while(ss>>word)
    {
      //if(    )
        cout<<word<<endl;
    }
}
InformationsquelleAutor user342231 | 2010-05-16

10 Comentarios

  1. 66

    Otra versión…

    Uso strtol, envolviéndola en el interior de una simple función para ocultar su complejidad :

    inline bool isInteger(const std::string & s)
    {
       if(s.empty() || ((!isdigit(s[0])) && (s[0] != '-') && (s[0] != '+'))) return false;
    
       char * p;
       strtol(s.c_str(), &p, 10);
    
       return (*p == 0);
    }

    Por qué strtol ?

    Tan lejos como me encanta C++, a veces la API de C es la mejor respuesta como lo que me refiero:

    • mediante el uso de excepciones es una exageración para una prueba de que está autorizado a fallar
    • el temporal objeto de secuencia de la creación por parte del léxico de fundición es excesivo y más ineficientes cuando la biblioteca estándar de C tiene un poco conocido dedicada función que realiza el trabajo.

    ¿Cómo funciona ?

    strtol parece bastante crudos a primera vista, por lo que una explicación va a hacer que el código sea más sencillo de leer :

    strtol va a analizar la cadena, deteniéndose en el primer carácter que no puede ser considerado parte de un entero. Si usted proporciona p (como hice anteriormente), establece p a la derecha en este primer no-entero carácter.

    Mi razonamiento es que si p no se establece al final de la cadena (el carácter 0), entonces existe un no-entero de caracteres en la cadena s, significado s no es una forma correcta entero.

    Las primeras pruebas están ahí para eliminar la esquina de los casos (espacios, cadena vacía, etc.).

    Esta función debe ser, por supuesto, adaptado a sus necesidades (son los principales espacios de un error? etc.).

    Fuentes :

    Ver la descripción de strtol en: http://en.cppreference.com/w/cpp/string/byte/strtol.

    Ver, también, la descripción de strtol‘s hermana funciones (strtod, strtoul, etc.).

    • +1, por mucho, la mejor respuesta. lexical_cast es una exageración y que las fronteras en una mala práctica.
    • Titarenco : lexical_cast is overkill and it borders on bad practice : Sólo cuando se utiliza sin cuidado, y lo mismo puede decirse de cualquier otra característica. El uso real de boost::lexical_cast es para el código genérico, o rápido y sucio código. el código Genérico: Cuando usted tiene un tipo desconocido de T, el uso de un interruptor para uso strtol, strtol, etc. es un error. El uso de un impulso::lexical_cast es lo correcto, proporcionando el impulso::lexical_cast especializaciones de los tipos adecuados para el uso eficiente. Rápido n»dirty código: Si ese código no necesita de la velocidad, entonces el uso de boost::lexical_cast es la manera más fácil de hacerlo.
    • ¿Por qué está usted hablando de las excepciones y lexical_cast ser excesivo e ineficiente, cuando no se miden (o, si no, no se muestran los resultados)?
  2. 56

    La aceptada respuesta va a dar un falso positivo, si la entrada es un número más el texto, porque «stol» se convierta los primeros dígitos e ignorar el resto.

    Me gusta la versión siguiente de la mayoría, ya que es un buen one-liner que no es necesario definir una función y puede simplemente copiar y pegar donde usted la necesite.

    #include <string>
    
    ...
    
    std::string s;
    
    bool has_only_digits = (s.find_first_not_of( "0123456789" ) == std::string::npos);

    EDIT: si te gusta esta aplicación, pero usted lo quiere usar como una función, entonces esto debe hacer:

    bool has_only_digits(const string s){
      return s.find_first_not_of( "0123456789" ) == string::npos;
    }
    • «es un buen one-liner que no es necesario definir una función y puede simplemente copiar y pegar donde usted la necesite», pero usted debe definir una función. Por favor, no copiar y pegar el código.
    • gracias, ordenados
    • ¿Qué acerca de los números negativos?
    • Es verdad, esto no funciona para los números negativos. Pero usted puede comprobar si el primer carácter es un + o un -, y si ese es el caso que acabamos de pasar el resto de la cadena.
    • Wow, esta es una gran respuesta! Nunca lo hubiera imaginado
    • Sólo funciona para los números enteros positivos
    • eso es cierto. Si le sucede a modificarlo para que funcione para ambos números enteros positivos y negativos yo estaría feliz de editar mi respuesta.

  3. 16

    Usted puede tratar de boost::lexical_cast. Se produce una bad_lexical_cast excepción si se produce un error.

    En su caso:

    int number;
    try
    {
      number = boost::lexical_cast<int>(word);
    }
    catch(boost::bad_lexical_cast& e)
    {
      std::cout << word << "isn't a number" << std::endl;
    }
  4. 8

    Si usted está comprobando si word es un número, que no es demasiado difícil:

    #include <ctype.h>

    string word;
    bool isNumber = true;
    for(string::const_iterator k = word.begin(); k != word.end(); ++k)
        isNumber &&= isdigit(*k);

    Optimizar como se desee.

  5. 4

    Puede utilizar boost::lexical_cast, como se ha sugerido, pero si usted tiene algún conocimiento previo acerca de las cadenas (es decir, que si una cadena contiene un literal entero no tendrá ningún espacio, o que los números enteros son nunca por escrito con exponentes), entonces el despliegue de su propia función, debe ser más eficiente, y no es particularmente difícil.

  6. 4

    Uso el todo poderoso C stdio/funciones de cadena:

    int dummy_int;
    int scan_value = std::sscanf( some_string.c_str(), "%d", &dummy_int);
    
    if (scan_value == 0)
        //does not start with integer
    else
        //starts with integer
    • Si sscanf devuelve el número de artículos que coinciden, entonces su ejemplo (comentarios) está equivocado. O no me malinterprete algo?
  7. 3

    Ok, a mi modo de ver tienes 3 opciones.

    1: Si usted simplemente desea verificar si el número es un número entero, y no se preocupan acerca de su conversión, sino que, simplemente, desean mantener como una cadena y no se preocupan acerca de los posibles desbordamientos, comprobando si coincide con una expresión regular para un entero sería lo ideal aquí.

    2: Usted puede usar el boost::lexical_cast y, a continuación, coger un potencial de boost::bad_lexical_cast excepción a ver si el error de conversión. Esto funciona bien si usted puede usar el boost y si fallando la conversión es una condición excepcional.

    3: Rollo de su propia función similar a lexical_cast que comprueba la conversión y devuelve true o false dependiendo de si es correcta o no. Esto funcionaría en el caso de 1 & 2 no se ajuste a sus requisitos.

    • Pick A. Regex no dicen si se sobrepasa el rango de un entero.
    • Oh, a la derecha, se olvidó de desbordamiento, por supuesto, va a huelga.
    • Pregunta Original no menciona que quieran comprobar por desbordamientos o incluso querer utilizar un número como un número entero. Para todos los que me conoce, se está pensando en guardar el número en una cadena para evitar tales límites.
    • Bien, he intentado cambiar la respuesta para incluir las 3 opciones que tenía originalmente la lista, con una razón de cada uno de ellos.
  8. 1
    template <typename T>
    const T to(const string& sval)
    {
            T val;
            stringstream ss;
            ss << sval;
            ss >> val;
            if(ss.fail())
                    throw runtime_error((string)typeid(T).name() + " type wanted: " + sval);
            return val;
    }

    Y, a continuación, se puede utilizar como que:

    double d = to<double>("4.3");

    o

    int i = to<int>("4123");
    • Yo prefiero usar el boost::lexical_cast.
    • Así lo hace el ejemplo original.
  9. 1

    He modificado paercebal del método para satisfacer mis necesidades:

    typedef std::string String;    
    
    bool isInt(const String& s, int base){
       if(s.empty() || std::isspace(s[0])) return false ;
       char * p ;
       strtol(s.c_str(), &p, base) ;
       return (*p == 0) ;
    }
    
    
    bool isPositiveInt(const String& s, int base){
       if(s.empty() || std::isspace(s[0]) || s[0]=='-') return false ;
       char * p ;
       strtol(s.c_str(), &p, base) ;
       return (*p == 0) ;
    }
    
    
    bool isNegativeInt(const String& s, int base){
       if(s.empty() || std::isspace(s[0]) || s[0]!='-') return false ;
       char * p ;
       strtol(s.c_str(), &p, base) ;
       return (*p == 0) ;
    }

    Nota:

    1. Puede comprobar diversas bases (binario, oct, hex y otros)
    2. Hacer seguro de que no pase 1, valor negativo o valor >36 como base.
    3. Si pasa 0 como la base, que detectará automáticamente la base de e.e para una cadena de inicio con 0x será tratada como hex y cadena de inicio con 0 será tratada como oct. Los personajes son insensibles a mayúsculas /minúsculas.
    4. Cualquier espacio en blanco en la cadena hará devolver false.
  10. 1

    Aquí hay otra solución.

    try
    {
      (void) std::stoi(myString); //cast to void to ignore the return value   
      //Success! myString contained an integer
    } 
    catch (const std::logic_error &e)
    {   
      //Failure! myString did not contain an integer
    }
    • Las excepciones no deben ser utilizados para las operaciones normales y de control de flujo. Sólo deben ser utilizados para… adivinaron: excepciones. 😉
    • Gracias por los comentarios!

Dejar respuesta

Please enter your comment!
Please enter your name here