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.