Come posso convertire uno std :: string in int?


484

Basta una domanda veloce. Ho guardato un po 'in giro per Internet e ho trovato alcune soluzioni, ma nessuna di queste ha ancora funzionato. Sto cercando di convertire una stringa in un int e non intendo i codici ASCII.

Per una rapida analisi, siamo passati in un'equazione come una stringa. Dobbiamo scomporlo, formattarlo correttamente e risolvere le equazioni lineari. Ora, dicendo questo, non sono in grado di convertire una stringa in un int.

So che la stringa sarà nel formato (-5) o (25) ecc. Quindi è sicuramente un int. Ma come lo estraiamo da una stringa?

Un modo in cui stavo pensando è quello di eseguire un ciclo for / while attraverso la stringa, controllare una cifra, estrarre tutte le cifre dopo quella e quindi vedere se c'era un '-' iniziale, se c'è, moltiplicare l'int per - 1.

Sembra un po 'troppo complicato per un problema così piccolo. Qualche idea?


9
Ci hai provato atoi()?
i_am_jorf,



7
@Chad Quindi stai raccomandando di usare un'intera libreria per qualcosa che il linguaggio può fare comunque con le librerie standard?
Bojangles,

6
@Brandon, se hai un std::string myString, e vuoi usare atoi, allora vuoi dire atoi(myString.c_str()).
Robᵩ

Risposte:


726

In C ++ 11 ci sono alcune nuove funzioni di conversione da std::string un tipo di numero.

Quindi invece di

atoi( str.c_str() )

Puoi usare

std::stoi( str )

dov'è il strtuo numero comestd::string .

Ci sono versioni per tutte le versioni di numeri: long stol(string), float stof(string), double stod(string), ... vedi http://en.cppreference.com/w/cpp/string/basic_string/stol


5
Per problemi con std :: stoi vedi stackoverflow.com/a/6154614/195527 : verrà convertito "11x"per intero 11.
CC.

5
#include <stdlib.h> / * atoi * /
Ulad Kasach

4
@CC Questo è anche il comportamento di atoi: cplusplus.com/reference/cstdlib/atoi "La stringa può contenere caratteri aggiuntivi dopo quelli che formano il numero integrale, che vengono ignorati e non hanno alcun effetto sul comportamento di questa funzione."
Stregone di stagno

4
Ti dispiacerebbe aggiornare questa risposta con from_charsda C ++ 17? Dovrebbe essere ordini di grandezza più veloci di stoi.
NathanOliver,

stoidovrebbe essere preferito. Vedi Perché non dovrei usare atoi ()?
phuclv, il

57
std::istringstream ss(thestring);
ss >> thevalue;

Per essere completamente corretto, ti consigliamo di controllare i flag di errore.


2
Questo non verrà estratto -5da (-5).
Nawaz,

@Nawaz, i genitori sono effettivamente lì, o è così che l'OP presenta le sue stringhe?
Winston Ewert,

Non lo so. Sto solo sottolineando la limitazione dell'approccio.
Nawaz,

16
@Nawaz, Inoltre, non può operare sull'ingresso "WERWER". Non penso che le parentesi facciano effettivamente parte della sua stringa effettiva e non penso che il fatto che non le analizzi sia rilevante.
Winston Ewert,

4
@Nawaz, ok ... Non prendo la parola in quel modo ma vedo come potresti.
Winston Ewert,

44

Le possibili opzioni sono descritte di seguito:

1. Prima opzione: 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

Questo è un errore (mostrato anche da cppcheck) perché "scanf senza limiti di larghezza di campo può andare in crash con enormi dati di input su alcune versioni di libc" (vedi qui e qui ).

2. Seconda opzione: 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
        }   

Questa soluzione è breve ed elegante, ma è disponibile solo su compilatori conformi a C ++ 11.

3. Terza opzione: stream

    #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 ??

Tuttavia, con questa soluzione è difficile distinguere tra input errato (vedere qui ).

4. Quarta opzione: lexical_cast di Boost

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

Tuttavia, questo è solo un wrapper di sstreame la documentazione suggerisce di utilizzare sstreamper una migliore gestione degli errori (vedi qui ).

5. Quinta opzione: strto * ()

Questa soluzione è molto lunga, a causa della gestione degli errori, ed è descritta qui. Poiché nessuna funzione restituisce un semplice int, è necessaria una conversione in caso di numero intero (vedere qui per come è possibile ottenere questa conversione).

6. Sesta opzione: 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     

conclusioni

Riassumendo, la soluzione migliore è C ++ 11 std::stoi()o, come seconda opzione, l'uso delle librerie Qt. Tutte le altre soluzioni sono scoraggiate o buggy.


Fisso. Grazie per aver segnalato.
Claudio,

Bellissimo riassunto, molte grazie. Posso suggerire di aggiungere un commento iniziale che suggerisce la soluzione finale in modo che solo le persone interessate ai dettagli continuino a leggere?
Luca

1
questa dovrebbe essere la risposta accettata, anche tu hai dimenticato (o meglio dovresti aggiungere perché è una vecchia risposta) from_chars
xception


9

Che dire di Boost.Lexical_cast ?

Ecco il loro esempio:

L'esempio seguente tratta gli argomenti della riga di comando come una sequenza di dati numerici:

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);
        }
    }
    ...
}

Il collegamento è interrotto. Potresti risolverlo?
Yuchen Zhong

5

Certo, la mia soluzione non funzionerebbe con numeri interi negativi, ma estrarrà tutti i numeri interi positivi dal testo di input contenente numeri interi. Fa uso delle numeric_onlyimpostazioni locali:

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

Testo di input:

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

Numeri di uscita:

 5
25
7987
78
9878

La classe numeric_onlyè definita come:

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 online completa: http://ideone.com/dRWSj


4

Probabilmente è un po 'eccessivo, ma boost::lexical_cast<int>( theString )dovrebbe funzionare abbastanza bene.


Un errore di battitura Dovrebbe essere semplicemente boost::lexical_cast<int>( theString )(dove si theStringtrova il nome della variabile che contiene la stringa in cui si desidera convertire int).
James Kanze,


1

In Windows, è possibile utilizzare:

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, è stringstreamnecessario specificare la base se è necessario interpretare esadecimale.


1

Bene, molte risposte, molte possibilità. Quello che mi manca qui è un metodo universale che converte una stringa in diversi tipi integrali C ++ (short, int, long, bool, ...). Ho trovato la seguente soluzione:

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

Ecco alcuni esempi di utilizzo:

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

Perché non usare semplicemente l'operatore di output di stringstream per convertire una stringa in un tipo integrale? Ecco la risposta: supponiamo che una stringa contenga un valore che supera il limite per il tipo integrale previsto. Ad esempio, su Wndows 64 max int è 2147483647. Assegniamo a una stringa un valore max int + 1: string str = "2147483648". Ora, quando converti la stringa in un int:

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

x diventa 2147483647, il che è sicuramente un errore: la stringa "2147483648" non doveva essere convertita in int 2147483647. La funzione fornita in IntegralType rileva tali errori e genera un'eccezione.


0

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

Produzione:

2001, Odissea nello spazio: 2001 e [, Odissea nello spazio]

40c3: 16579

-10010110001: -1201

0x7f: 127


0

Il mio codice:

#include <iostream>
using namespace std;

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

    return 0;
}

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

0

Per convertire dalla rappresentazione di stringa in valore intero, possiamo usare std :: stringstream.

se il valore convertito è fuori intervallo per il tipo di dati intero, restituisce INT_MIN o INT_MAX.

Inoltre, se il valore della stringa non può essere rappresentato come un tipo di dati int valido, viene restituito 0.

#include 
#include 
#include 

int main() {

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

Uscita: 50

Come per l'output sopra, possiamo vederlo convertito da numeri di stringa in numero intero.

Sorgente e altro su stringa in int c ++


-2

Versione a una riga: long n = strtol(s.c_str(), NULL, base); .

( sè la stringa ed baseè un int2, 8, 10, 16.)

È possibile fare riferimento a questo link per ulteriori dettagli su strtol.


L'idea principale è quella di utilizzare la strtolfunzione, inclusa in cstdlib.

Dal momento strtolche gestisce solo con l' chararray, abbiamo bisogno di convertire stringin chararray. Puoi fare riferimento a questo link .

Un esempio:

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

che produrrà:

1111000001011010
61530
f05a
1111000001011010

-3

c'è un altro modo semplice: supponiamo di avere un personaggio simile c='4' questo, quindi puoi fare uno di questi passaggi:

1 °: 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 .

il secondo modo:

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


1
La domanda riguarda la conversione da stringa intpiuttosto che da chara string.
Yuchen Zhong,

buggy e non corrispondente alla domanda
caoanan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.