2010-12-14 11 views
54

Powiel możliwe:
How to parse a string to an int in C++?C++ parse int z ciągiem

Zrobiłem rozeznanie i niektórzy mówią, aby używać acji i inni mówią, że to źle, a ja nie mogę dostać to działa tak czy inaczej.

Po prostu chcę zapytać się, jaki jest właściwy sposób zamiany ciągu na int.

Dzięki!

+3

prawdopodobnie miałeś na myśli ('std ::') 'string s =" 10 "'. – lijie

+1

Duplikat http://stackoverflow.com/questions/200090/how-do-you-convert-ac-string-to-an-int i http://stackoverflow.com/questions/194465/how-to-parse -a-string-to-an-int-in-c –

+0

@lijie - może, ale nigdy nie mówię tego w moim kodzie ... powinienem być? – kralco626

Odpowiedz

64
  • C++ 11, należy std::stoi jako:

    std::string s = "10"; 
    int i = std::stoi(s); 
    

    Należy zauważyć, że std::stoi rzuci wyjątek typu std::invalid_argument, że konwersja nie może być wykonane, albo std::out_of_range jeśli wyniki konwersji w przelew (tj gdy wartość ciągu jest zbyt duża dla typu int). Można użyć std::stol lub std:stoll, jednak w przypadku, gdy int wydaje się zbyt mały dla wejściowego ciągu znaków.

  • w C++ 03/98, jedną z następujących czynności można stosować:

    std::string s = "10"; 
    int i; 
    
    //approach one 
    std::istringstream(s) >> i; //i is 10 after this 
    
    //approach two 
    sscanf(s.c_str(), "%d", &i); //i is 10 after this 
    

Należy zauważyć, że powyższe dwa podejścia byłoby nie do wejścia s = "10jh". Zwrócą 10, zamiast zgłaszać błąd. Bezpiecznym i niezawodnym podejściem jest napisanie własnej funkcji, która analizuje ciąg wejściowy i weryfikowanie każdego znaku w celu sprawdzenia, czy jest to cyfra, czy nie, a następnie działa odpowiednio. Oto jeden solidny implemtation (przetestowane chociaż) wersja

int to_int(char const *s) 
{ 
    if (s == NULL || *s == '\0') 
     throw std::invalid_argument("null or empty string argument"); 

    bool negate = (s[0] == '-'); 
     if (*s == '+' || *s == '-')  
        ++s; 

    if (*s == '\0') 
     throw std::invalid_argument("sign character only."); 

     int result = 0; 
     while(*s) 
     { 
          if (*s >= '0' && *s <= '9') 
          { 
              result = result * 10  - (*s - '0');  //assume negative number 
          } 
          else 
              throw std::invalid_argument("invalid input string"); 
          ++s; 
     } 
     return negate ? result : -result; //-result is positive! 
}  

Roztwór ten jest lekko zmodyfikowana my another solution.

+4

Ogólnie, unikam 'atoi' w danych wprowadzanych przez użytkownika, ponieważ kiedy otrzymasz 0, nie wiesz czy to jest ponieważ ciąg zawierał "0" lub ponieważ był niepoprawny. –

+0

Atoi i itoa często powodują problemy, więc zalecam unikanie tych funkcji. Zamiast tego użyłbym boost lub stringstream. – RageD

+0

dobre na szybki projekt, ale ze względu na jego prostotę – kralco626

7

Można użyć istringstream.

string s = "10"; 

// create an input stream with your string. 
istringstream is(str); 

int i; 
// use is like an input stream 
is >> i; 
12

Można użyć boost::lexical_cast:

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

int main(int argc, char* argv[]){ 
std::string s1 = "10"; 
std::string s2 = "abc"; 
int i; 

    try { 
     i = boost::lexical_cast<int>(s1); 
    } 
    catch(boost::bad_lexical_cast & e){ 
     std::cout << "Exception caught : " << e.what() << std::endl; 
    } 

    try { 
     i = boost::lexical_cast<int>(s2); 
    } 
    catch(boost::bad_lexical_cast & e){ 
     std::cout << "Exception caught : " << e.what() << std::endl; 
    } 

    return 0; 
} 
+9

boost lexical_cast jest bardzo bardzo bardzo powolny. również fakt, że wymaga on obsługi wyjątków, czyni go jeszcze bardziej szesnastkowym. tylko dobre na wejście, które przychodzi z prędkością użytkownika, nic więcej. –

+0

@dman: rzeczywiście leksykalny_cast jest wolniejszy niż atoi/strtol/sscanf, ale 1) OP nie pyta o najszybszą drogę (i pytanie jest oznaczone jako C++) 2) lexical_cast to ogólne rozwiązanie, a będąc częścią Boost, możesz powiedzieć ci kilka rzeczy o jakości implementacji 3) wyjątek bad_lexical_cast zapewnia sposób na wykrycie błędów konwersji, niewielką cenę za prawidłową obsługę błędów 4) jeśli leksykonem jest wąskie gardło, bardzo łatwo jest zaimplementować specjalizację dla typów danych: –

+0

+1 w tej sprawie . Podoba mi się twoja argumentacja i naprawdę podoba mi się to rozwiązanie. Będąc osobą z Java, lubię próbować złapać i prawdopodobnie wykorzystam to rozwiązanie w przyszłości. – kralco626

9

Nie ma "właściwy sposób". Jeśli chcesz uniwersalne (ale nieoptymalne) rozwiązanie, możesz użyć boost :: leksykalnej obsady.

Typowym rozwiązaniem dla języka C++ jest użycie operatora std :: ostream i < <. Możesz użyć metody stringstream i stringstream :: str() do konwersji na łańcuch.

Jeśli naprawdę wymagają szybki mechanizm (pamiętaj regułę 20/80) można szukać „dedykowanym” rozwiązania jak http://www.partow.net/programming/strtk/index.html

poważaniem,
Marcin

+19

"Nie ma mowy w żaden sposób" "- musisz kochać język, w którym nie ma" właściwej drogi "do parsowania ciągu ...:( – kralco626

4

Niektóre Podręczne funkcje (jeśli nie używasz Boost):

template<typename T> 
std::string ToString(const T& v) 
{ 
    std::ostringstream ss; 
    ss << v; 
    return ss.str(); 
} 

template<typename T> 
T FromString(const std::string& str) 
{ 
    std::istringstream ss(str); 
    T ret; 
    ss >> ret; 
    return ret; 
} 

Przykład:

int i = FromString<int>(s); 
std::string str = ToString(i); 

Działa dla dowolnych typów strumieniowych (pływaki itp.). Będziesz musiał #include <sstream>, a być może także #include <string>.

+2

To jest rozwiązanie :: lexical_cast używa – Marcin

+0

Program Actualla boost :: lexical_cast nie używa oryginalnych strumieni std stringów, ale niektóre podkręcone klasy strumienia, które powinny sprawić, że będzie trochę szybszy niż te funkcje. sprawdzenie (w tym sprawdzenie, czy dane wejściowe zostały w całości zużyte przez operatora wyciągu), więc jest o wiele bezpieczniejsze w użyciu niż te dwie funkcje. –