Jak przekonwertować std :: string na int?


484

Wystarczy krótkie pytanie. Rozejrzałem się po Internecie i znalazłem kilka rozwiązań, ale żadne z nich jeszcze nie działało. Patrząc na konwersję ciągu na int i nie mam na myśli kodów ASCII.

W celu szybkiego skrócenia przekazujemy równanie jako ciąg znaków. Mamy go rozbić, poprawnie sformatować i rozwiązać równania liniowe. Mówiąc to, nie jestem w stanie przekonwertować ciągu na wartość int.

Wiem, że ciąg będzie w formacie (-5) lub (25) itd., Więc zdecydowanie jest to int. Ale jak wyciągamy to z łańcucha?

Jednym ze sposobów, w jaki myślałem, jest przepuszczenie pętli for / while przez ciąg, sprawdzenie cyfry, wyodrębnienie wszystkich cyfr po tym, a następnie sprawdzenie, czy na początku było „-”, jeśli istnieje, pomnóż int przez - 1.

Wydaje się to jednak nieco skomplikowane w przypadku tak małego problemu. Jakieś pomysły?


9
Próbowałeś atoi()?
i_am_jorf



7
@Chad Więc zalecamy, aby używał całej biblioteki do czegoś, co język może zrobić ze standardowymi bibliotekami?
Bojangles,

6
@Brandon, jeśli masz std::string myStringi chcesz użyć atoi, to chcesz powiedzieć atoi(myString.c_str()).
Robᵩ

Odpowiedzi:


726

W C ++ 11 jest kilka nowych, ciekawych funkcji konwersji z std::stringna typ liczbowy.

Więc zamiast

atoi( str.c_str() )

możesz użyć

std::stoi( str )

gdzie strjest twój numer jako std::string.

Istnieje wersja dla wszystkich smaków liczb: long stol(string), float stof(string), double stod(string), ... zobacz http://en.cppreference.com/w/cpp/string/basic_string/stol


5
W przypadku problemów ze std :: stoj zobacz stackoverflow.com/a/6154614/195527 : konwertuje "11x"na liczbę całkowitą 11.
CC.

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

4
@CC to też zachowanie atoi: cplusplus.com/reference/cstdlib/atoi „Ciąg może zawierać dodatkowe znaki po które tworzą integralną liczby, które są ignorowane i nie mają wpływu na zachowanie tej funkcji”
Tin Wizard

4
Czy mógłbyś zaktualizować tę odpowiedź za pomocą from_charsC ++ 17? Ma być o rząd wielkości szybszy niż stoi.
NathanOliver

stoipowinno być preferowane. Zobacz dlaczego nie powinienem używać atoi ()?
phuclv

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

Aby być w pełni poprawnym, sprawdź flagi błędów.


2
To nie będzie wyciąg -5z (-5).
Nawaz

@Nawaz, czy pareny faktycznie tam są, czy też tak właśnie OP prezentuje swoje struny?
Winston Ewert,

Nie wiem Wskazuję tylko na ograniczenie podejścia.
Nawaz

16
@Nawaz, nie może również działać na wejściu „WERWER”. Nie sądzę, że pareny są częścią jego rzeczywistej struny i nie sądzę, że fakt, że ich nie analizuję, jest istotny.
Winston Ewert

4
@Nawaz, ok ... Nie rozumiem tego w ten sposób, ale widzę, jak mogłeś.
Winston Ewert

44

Możliwe opcje opisano poniżej:

1. Pierwsza opcja: 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

Jest to błąd (również pokazany przez cppcheck), ponieważ „scanf bez ograniczeń szerokości pola może ulec awarii z ogromnymi danymi wejściowymi w niektórych wersjach libc” (patrz tutaj i tutaj ).

2. Druga opcja: 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
        }   

To rozwiązanie jest krótkie i eleganckie, ale jest dostępne tylko w kompilatorach zgodnych z C ++ 11.

3. Trzecia opcja: sstreams

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

Jednak dzięki temu rozwiązaniu trudno jest odróżnić złe dane wejściowe (patrz tutaj ).

4. Czwarta opcja: 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
        }

Jest to jednak tylko opakowanie sstream, a dokumentacja sugeruje użycie w sstreamcelu lepszego zarządzania błędami (patrz tutaj ).

5. Piąta opcja: strto * ()

To rozwiązanie jest bardzo długie ze względu na zarządzanie błędami i zostało opisane tutaj. Ponieważ żadna funkcja nie zwraca zwykłej liczby całkowitej, konwersja jest konieczna w przypadku liczby całkowitej (zobacz tutaj, jak można uzyskać tę konwersję).

6. Szósta opcja: 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     

Wnioski

Podsumowując, najlepszym rozwiązaniem jest C ++ 11 std::stoi()lub, jako druga opcja, użycie bibliotek Qt. Wszystkie inne rozwiązania są odradzane lub zawierają błędy.


Naprawiony. Dziękujemy za zgłoszenie.
Claudio,

Piękne podsumowanie, wielkie dzięki. Czy mogę zasugerować dodanie wstępnego komentarza sugerującego ostateczne rozwiązanie, aby tylko osoby zainteresowane szczegółami czytały dalej?
luca

1
ten powinien być zaakceptowany odpowiedź, również zapomniał (albo raczej powinien dodać przyczyna to stary odpowiedź) from_chars
xception


9

Co z Boost.Lexical_cast ?

Oto ich przykład:

Poniższy przykład traktuje argumenty wiersza poleceń jako ciąg danych liczbowych:

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

Link jest zepsuty. Czy możesz to naprawić?
Yuchen Zhong,

5

Wprawdzie moje rozwiązanie nie działałoby dla ujemnych liczb całkowitych, ale wyodrębni wszystkie dodatnie liczby całkowite z tekstu wejściowego zawierającego liczby całkowite. Wykorzystuje numeric_onlyustawienia regionalne:

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

Wprowadź tekst:

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

Wyjściowe liczby całkowite:

 5
25
7987
78
9878

Klasa numeric_onlyjest zdefiniowana jako:

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

Kompletne demo online: http://ideone.com/dRWSj


4

Prawdopodobnie jest to trochę przesada, ale boost::lexical_cast<int>( theString )powinno dobrze działać.


Literówka. Powinien to być po prostu boost::lexical_cast<int>( theString )(gdzie theStringjest nazwa zmiennej zawierającej ciąg, na który chcesz przekonwertować int).
James Kanze,


1

W systemie Windows możesz użyć:

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, stringstreammusisz określić podstawę, jeśli chcesz interpretować wartość szesnastkową.


1

Cóż, wiele odpowiedzi, wiele możliwości. Brakuje mi tutaj uniwersalnej metody, która konwertuje ciąg znaków na różne typy całek C ++ (short, int, long, bool, ...). Wymyśliłem następujące rozwiązanie:

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

Oto przykłady użycia:

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

Dlaczego po prostu nie użyć operatora strumienia wyjściowego do konwersji łańcucha na typ integralny? Oto odpowiedź: Powiedzmy, że łańcuch zawiera wartość, która przekracza limit zamierzonego typu całki. Na przykład na Wndows 64 max int wynosi 2147483647. Przypiszmy do ciągu wartość max int + 1: string str = "2147483648". Teraz podczas konwertowania ciągu na int:

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

x staje się 2147483647, co jest zdecydowanie błędem: ciąg „2147483648” nie miał zostać przekonwertowany na int 2147483647. Podana funkcja toIntegralType wykrywa takie błędy i zgłasza wyjątek.


0

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

Wynik:

2001, A Space Odyssey: 2001 i [, A Space Odyssey]

40c3: 16579

-10010110001: -1201

0x7f: 127


0

Mój kod:

#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

Aby przekonwertować reprezentację ciągu na wartość całkowitą, możemy użyć std :: stringstream.

jeśli przekonwertowana wartość jest poza zakresem dla typu danych liczb całkowitych, zwraca INT_MIN lub INT_MAX.

Również jeśli wartość ciągu nie może być reprezentowana jako poprawny typ danych int, zwracane jest 0.

#include 
#include 
#include 

int main() {

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

Wyjście: 50

Zgodnie z powyższymi danymi wyjściowymi możemy przekonwertować je z liczb ciągów na liczbę całkowitą.

Źródło i więcej w ciągu do int c ++


-2

Jedna z wersji linia: long n = strtol(s.c_str(), NULL, base);.

( sjest ciągiem i basejest inttaki jak 2, 8, 10, 16.)

Możesz zapoznać się z tym linkiem, aby uzyskać więcej informacji na temat strtol.


Podstawową ideą jest użycie strtolfunkcji, która jest zawarta w cstdlib.

Ponieważ strtoltylko obsługuje się z chartablicą, musimy przekonwertować stringna chartablicę. Możesz skorzystać z tego linku .

Przykład:

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

który wyświetli:

1111000001011010
61530
f05a
1111000001011010

-3

jest inny prosty sposób: załóżmy, że masz taką postać, c='4'dlatego możesz wykonać jeden z następujących kroków:

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

drugi sposób:

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


1
Pytanie dotyczy konwersji z stringna intzamiast z charna string.
Yuchen Zhong

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.