¿Cómo puedo convertir un std :: string a int?

484

Solo tengo una pregunta rápida. He buscado bastante en Internet y he encontrado algunas soluciones, pero ninguna de ellas ha funcionado todavía. Mirando la conversión de una cadena a un int y no me refiero a los códigos ASCII.

Para un desmantelamiento rápido, se nos pasa en una ecuación como una cadena. Debemos dividirlo, formatearlo correctamente y resolver las ecuaciones lineales. Ahora, al decir eso, no puedo convertir una cadena en un int.

Sé que la cadena tendrá el formato (-5) o (25), etc., así que definitivamente es un int. Pero, ¿cómo extraemos eso de una cadena?

Una forma en la que estaba pensando es ejecutar un bucle for / while a través de la cadena, verificar un dígito, extraer todos los dígitos después de eso y luego mirar para ver si había un '-' inicial, si es así, multiplique el int por - 1)

Sin embargo, parece un poco complicado para un problema tan pequeño. ¿Algunas ideas?

Brandon
fuente
99
¿Lo has intentado atoi()?
i_am_jorf
77
@Chad ¿Entonces está recomendando que use una biblioteca completa para algo que el lenguaje puede hacer con las bibliotecas estándar de todos modos?
Bojangles
66
@ Brandon, si tienes un std::string myStringy quieres usar atoi, entonces quieres decir atoi(myString.c_str()).
Robᵩ

Respuestas:

726

En C ++ 11 hay algunas funciones de conversión nuevas y agradables std::stringa un tipo de número.

Entonces en lugar de

atoi( str.c_str() )

puedes usar

std::stoi( str )

donde stres su número como std::string.

Hay versiones para todos los sabores de los números: long stol(string), float stof(string), double stod(string), ... ver http://en.cppreference.com/w/cpp/string/basic_string/stol

tgmath
fuente
55
Para problemas con std :: stoi, consulte stackoverflow.com/a/6154614/195527 : se convertirá "11x"a entero 11.
CC.
55
#include <stdlib.h> / * atoi * /
Ulad Kasach
44
@CC Ese es también el comportamiento de atoi: cplusplus.com/reference/cstdlib/atoi "La cadena puede contener caracteres adicionales después de los que forman el número integral, que se ignoran y no tienen efecto en el comportamiento de esta función".
Tin Wizard
44
¿Te importaría actualizar esta respuesta con from_charsC ++ 17? Se supone que son órdenes de magnitud más rápido que stoi.
NathanOliver
stoiDebería ser preferido. Consulte ¿Por qué no debería usar atoi ()?
phuclv
57
std::istringstream ss(thestring);
ss >> thevalue;

Para estar completamente correcto, querrá verificar las marcas de error.

Winston Ewert
fuente
2
Esto no se extraerá -5de (-5).
Nawaz
@Nawaz, ¿están los padres realmente allí, o es así como el OP presenta sus cadenas?
Winston Ewert
No lo sé. Solo estoy señalando la limitación del enfoque.
Nawaz
16
@Nawaz, tampoco puede funcionar en la entrada "WERWER". No creo que los padres sean realmente parte de su cadena real y no creo que el hecho de que no los analice sea relevante.
Winston Ewert
44
@Nawaz, está bien ... No tomo la palabra de esa manera, pero veo cómo pudiste.
Winston Ewert
44

Las posibles opciones se describen a continuación:

1. Primera opción: sscanf ()

    #include <cstdio>
    #include <string>

        int i;
        float f;
        double d;
        std::string str;

        // string -> integer
        if(sscanf(str.c_str(), "%d", &i) != 1)
            // error management

        // string -> float
        if(sscanf(str.c_str(), "%f", &f) != 1)
            // error management

        // string -> double 
        if(sscanf(str.c_str(), "%lf", &d) != 1)
            // error management

Este es un error (también mostrado por cppcheck) porque "scanf sin límites de ancho de campo puede bloquearse con grandes datos de entrada en algunas versiones de libc" (ver aquí y aquí ).

2. Segunda opción: std :: sto * ()

    #include <iostream>
    #include <string>

        int i;
        float f;
        double d;
        std::string str;

        try {
            // string -> integer
            int i = std::stoi(str);

            // string -> float
            float f = std::stof(str);

            // string -> double 
            double d = std::stod(str);
        } catch (...) {
            // error management
        }   

Esta solución es corta y elegante, pero solo está disponible en compiladores compatibles con C ++ 11.

3. Tercera opción: corrientes

    #include <string>
    #include <sstream>

        int i;
        float f;
        double d;
        std::string str;

        // string -> integer
        std::istringstream ( str ) >> i;

        // string -> float
        std::istringstream ( str ) >> f;

        // string -> double 
        std::istringstream ( str ) >> d;

        // error management ??

Sin embargo, con esta solución es difícil distinguir entre una entrada incorrecta (ver aquí ).

4. Cuarta opción: Boost's lexical_cast

    #include <boost/lexical_cast.hpp>
    #include <string>

        std::string str;

        try {
            int i = boost::lexical_cast<int>( str.c_str());
            float f = boost::lexical_cast<int>( str.c_str());
            double d = boost::lexical_cast<int>( str.c_str());
            } catch( boost::bad_lexical_cast const& ) {
                // Error management
        }

Sin embargo, esto es solo un resumen sstream, y la documentación sugiere utilizar sstreampara una mejor gestión de errores (ver aquí ).

5. Quinta opción: strto * ()

Esta solución es muy larga, debido a la gestión de errores, y se describe aquí. Como ninguna función devuelve un int simple, se necesita una conversión en caso de un número entero (vea aquí cómo se puede lograr esta conversión).

6. Sexta opción: Qt

    #include <QString>
    #include <string>

        bool ok;
        std::string;

        int i = QString::fromStdString(str).toInt(&ok);
        if (!ok)
            // Error management

        float f = QString::fromStdString(str).toFloat(&ok);
        if (!ok)
            // Error management 

        double d = QString::fromStdString(str).toDouble(&ok);
        if (!ok)
    // Error management     

Conclusiones

En resumen, la mejor solución es C ++ 11 std::stoi()o, como segunda opción, el uso de bibliotecas Qt. Todas las demás soluciones están desaconsejadas o tienen errores.

Claudio
fuente
Fijo. Gracias por informarnos.
Claudio
Hermoso resumen, muchas gracias. ¿Puedo sugerir agregar un comentario inicial que sugiera la solución final para que solo las personas interesadas en los detalles sigan leyendo?
luca
1
esta debería ser la respuesta aceptada, también se olvidó (o más bien debería agregar porque es una respuesta antigua) from_chars
xception
9

¿Qué pasa con Boost.Lexical_cast ?

Aquí está su ejemplo:

El siguiente ejemplo trata los argumentos de la línea de comandos como una secuencia de datos numéricos:

int main(int argc, char * argv[])
{
    using boost::lexical_cast;
    using boost::bad_lexical_cast;

    std::vector<short> args;

    while(*++argv)
    {
        try
        {
            args.push_back(lexical_cast<short>(*argv));
        }
        catch(bad_lexical_cast &)
        {
            args.push_back(0);
        }
    }
    ...
}
Robᵩ
fuente
El enlace está roto. ¿Podrías arreglarlo?
Yuchen Zhong
5

Es cierto que mi solución no funcionaría para enteros negativos, pero extraerá todos los enteros positivos del texto de entrada que contenga enteros. Hace uso de numeric_onlylocale:

int main() {
        int num;
        std::cin.imbue(std::locale(std::locale(), new numeric_only()));
        while ( std::cin >> num)
             std::cout << num << std::endl;
        return 0;
}

Texto de entrada:

 the format (-5) or (25) etc... some text.. and then.. 7987...78hjh.hhjg9878

Enteros de salida:

 5
25
7987
78
9878

La clase numeric_onlyse define como:

struct numeric_only: std::ctype<char> 
{
    numeric_only(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table()
    {
        static std::vector<std::ctype_base::mask> 
            rc(std::ctype<char>::table_size,std::ctype_base::space);

        std::fill(&rc['0'], &rc[':'], std::ctype_base::digit);
        return &rc[0];
    }
};

Demo en línea completa: http://ideone.com/dRWSj

Nawaz
fuente
4

Probablemente sea un poco exagerado, pero boost::lexical_cast<int>( theString )debería funcionar bastante bien.

James Kanze
fuente
Un error. Debe ser simplemente boost::lexical_cast<int>( theString )(donde theStringestá el nombre de la variable que contiene la cadena a la que desea convertir int).
James Kanze
1

En Windows, puedes usar:

const std::wstring hex = L"0x13";
const std::wstring dec = L"19";

int ret;
if (StrToIntEx(hex.c_str(), STIF_SUPPORT_HEX, &ret)) {
    std::cout << ret << "\n";
}
if (StrToIntEx(dec.c_str(), STIF_SUPPORT_HEX, &ret)) {
    std::cout << ret << "\n";
}

strtol, stringstreamdebe especificar la base si necesita interpretar hexdecimal.

Jichao
fuente
1

Bueno, muchas respuestas, muchas posibilidades. Lo que me falta aquí es un método universal que convierte una cadena a diferentes tipos integrales de C ++ (short, int, long, bool, ...). Se me ocurrió la siguiente solución:

#include<sstream>
#include<exception>
#include<string>
#include<type_traits>

using namespace std;

template<typename T>
T toIntegralType(const string &str) {
    static_assert(is_integral<T>::value, "Integral type required.");
    T ret;
    stringstream ss(str);
    ss >> ret;
    if ( to_string(ret) != str)
        throw invalid_argument("Can't convert " + str);
    return ret;
}

Aquí hay ejemplos de uso:

string str = "123";
int x = toIntegralType<int>(str); // x = 123

str = "123a";
x = toIntegralType<int>(str); // throws exception, because "123a" is not int

str = "1";
bool y = toIntegralType<bool>(str); // y is true
str = "0";
y = toIntegralType<bool>(str); // y is false
str = "00";
y = toIntegralType<bool>(str); // throws exception

¿Por qué no simplemente usar el operador de salida de secuencia de cadena para convertir una cadena en un tipo integral? Aquí está la respuesta: Digamos que una cadena contiene un valor que excede el límite para el tipo integral previsto. Por ejemplo, en Wndows 64 max int es 2147483647. Asignemos a una cadena un valor max int + 1: string str = "2147483648". Ahora, al convertir la cadena a un int:

stringstream ss(str);
int x;
ss >> x;

x se convierte en 2147483647, lo que definitivamente es un error: no se suponía que la cadena "2147483648" se convirtiera al int 2147483647. La función proporcionada toIntegralType detecta dichos errores y genera una excepción.

Andrushenko Alexander
fuente
0

De http://www.cplusplus.com/reference/string/stoi/

// stoi example
#include <iostream>   // std::cout
#include <string>     // std::string, std::stoi

int main ()
{
  std::string str_dec = "2001, A Space Odyssey";
  std::string str_hex = "40c3";
  std::string str_bin = "-10010110001";
  std::string str_auto = "0x7f";

  std::string::size_type sz;   // alias of size_t

  int i_dec = std::stoi (str_dec,&sz);
  int i_hex = std::stoi (str_hex,nullptr,16);
  int i_bin = std::stoi (str_bin,nullptr,2);
  int i_auto = std::stoi (str_auto,nullptr,0);

  std::cout << str_dec << ": " << i_dec << " and [" << str_dec.substr(sz) << "]\n";
  std::cout << str_hex << ": " << i_hex << '\n';
  std::cout << str_bin << ": " << i_bin << '\n';
  std::cout << str_auto << ": " << i_auto << '\n';

  return 0;
}

Salida:

2001, Una odisea del espacio: 2001 y [, Una odisea del espacio]

40c3: 16579

-10010110001: -1201

0x7f: 127

usuario7967189
fuente
0

Mi código:

#include <iostream>
using namespace std;

int main()
{
    string s="32";  //String
    int n=stoi(s);  //Convert to int
    cout << n + 1 << endl;

    return 0;
}
Gonçalo Garrido
fuente
0
ll toll(string a){
    ll ret=0;
    bool minus=false;
    for(auto i:a){
        if(i=='-'){ minus=true; continue; }
        ret*=10;
        ret+=(i-'0');
    } if(minus) ret*=-1;
    return ret;
    # ll is defined as, #define ll long long int
    # usage: ll a = toll(string("-1234"));
}
Amey Kudari
fuente
0

Para convertir de una representación de cadena a un valor entero, podemos usar std :: stringstream.

Si el valor convertido está fuera de rango para el tipo de datos entero, devuelve INT_MIN o INT_MAX.

Además, si el valor de la cadena no se puede representar como un tipo de datos int válido, se devuelve 0.

#include 
#include 
#include 

int main() {

    std::string x = "50";
    int y;
    std::istringstream(x) >> y;
    std::cout << y << '\n';
    return 0;
}

Salida: 50

Según el resultado anterior, podemos verlo convertido de números de cadena a número entero.

Fuente y más en cadena a int c ++

Bala Singh
fuente
-2

Versión de una línea: long n = strtol(s.c_str(), NULL, base); .

( ses la cadena y basees unint tal como 2, 8, 10, 16.)

Puede consultar este enlace para obtener más detalles de strtol.


La idea central es utilizar la strtolfunción, que se incluye encstdlib .

Dado que strtolsolo se maneja con charmatriz, necesitamos convertir stringa charmatriz. Puedes consultar este enlace .

Un ejemplo:

#include <iostream>
#include <string>   // string type
#include <bitset>   // bitset type used in the output

int main(){
    s = "1111000001011010";
    long t = strtol(s.c_str(), NULL, 2); // 2 is the base which parse the string

    cout << s << endl;
    cout << t << endl;
    cout << hex << t << endl;
    cout << bitset<16> (t) << endl;

    return 0;
}

que dará como resultado:

1111000001011010
61530
f05a
1111000001011010
Hansimov
fuente
-3

hay otra manera fácil: supongamos que tienes un personaje como c='4' por lo tanto, puede realizar uno de estos pasos:

1er: int q

q=(int) c ; (q is now 52 in ascii table ) . q=q-48; remember that adding 48 to digits is their ascii code .

la segunda forma:

q=c-'0'; the same , character '0' means 48

novato
fuente
1
La pregunta es sobre la conversión de stringa intmás que de chara string.
Yuchen Zhong
con errores y no coincide con la pregunta
caoanan