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.