2010-12-14 23 views
54

Olası Çoğalt:
How to parse a string to an int in C++?C++ ayrıştırma int

biraz araştırma yapmış ve bazı insanların ATIO kullanmak demek ve diğerleri kötü olduğunu söylüyorlar ve ben alamıyorum Yine de işe yarayacak.

Sadece bir diske sormak istiyorum, bir dizeyi int'ye dönüştürmenin doğru yolu nedir?

string s = "10"; 
int i = s....? 

Teşekkürler!

+3

Muhtemelen (std :: ') dizgisi s =" 10 "' anlamına geliyordu. – lijie

+1

http://stackoverflow.com/questions/200090/how-do-you-convert-ac-string-to-an-int ve http://stackoverflow.com/questions/194465/how-to-parse sayfasının kopyası -a-string-to-an-int-in-c –

+0

@lijie - belki, ama bunu asla kodumda söylemedim ... Olmalı mıyım? – kralco626

cevap

64
  • C++ 11, kullanma std::stoi olarak:

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

    std::stoi dönüştürme işlemi olamaz tip std::invalid_argument ait istisna, ya da taşma dönüştürme sonuçları ise std::out_of_range olabilir (yani, dize değeri int türü için çok büyük olduğunda). std::stol veya std:stoll'u kullanabilirsiniz, ancak int giriş dizesi için çok küçük görünüyor. Gelen

  • C++, aşağıdakilerden herhangi biri kullanılabilir/98 03: yukarıdaki iki yaklaşım giriş s = "10jh" başarısız olacağı

    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 
    

not edin. Hatayı bildirmek yerine 10 döndürürler. Bu nedenle güvenli ve sağlam yaklaşım, giriş dizesini ayrıştıran kendi fonksiyonunuzu yazmaktır ve her bir karakterin rakam olup olmadığını kontrol etmek için doğrulayın ve sonra buna göre çalışın. my another solution arasında

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

Bu çözelti hafifçe değiştirilmiş versiyonu: Burada tek bir dayanıklı implemtation (denenmemiş de).

+4

Genelde, kullanıcı tarafından sağlanan girişte atoi'den kaçınacağım, çünkü 0 aldığınızda, Dize, "0" 'içeriyordu ya da geçersiz olduğu için. –

+0

Atoi ve itoa sıklıkla sorunlara neden olur bu yüzden bu işlevlerden kaçınmanızı tavsiye ederim. Bunun yerine destek veya stringstream kullanırdım. – RageD

+0

basit bir proje için iyi olsa da, basitlik nedeniyle – kralco626

7

istringstream'u kullanabilirsiniz.

string s = "10"; 

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

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

Sen boost::lexical_cast kullanabilirsiniz:

#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 çok çok çok yavaş. Ayrıca istisna işleme gerektirdiği gerçeği, onu daha da küfürbaz hale getirir. Kullanıcı hızlarında gelen girişler için sadece iyi, başka hiçbir şey. –

+0

@dman: reallyed lexical_cast atoi/strtol/sscanf'den daha yavaş fakat 1) OP en hızlı yolu sormadı (ve soru C++ olarak etiketlendi) 2) lexical_cast genel bir çözümdür ve Boost'un bir parçası olmak size bazı şeyleri anlatabilir Uygulamanın kalitesi hakkında 3) bad_lexical_cast istisnası size dönüşüm hataları, uygun hata işleme için ödemek için küçük bir fiyat tespit etmek için bir yol sağlar 4) lexical_cast senin darboğaz bu veri türleri –

+0

+1 veri türleri için bir uzmanlık uygulamak oldukça kolay . Tartışmayı beğendim ve çözümü gerçekten seviyorum. Beğendiğim bir Java kullanıcısıyım, yakalamaya çalışın ve bu çözümü gelecekte de kullanabilirsiniz. – kralco626

9

"doğru yol" yoktur. Evrensel (ama suboptimal) bir çözüm istiyorsanız, bir boost :: lexical cast kullanabilirsiniz.

C++ için yaygın bir çözüm, std :: ostream ve < < işlecini kullanmaktır. Dizeye dönüştürmek için bir stringstream ve stringstream :: str() yöntemini kullanabilirsiniz.Eğer gerçekten hızlı bir mekanizma gerektiriyorsa

(eğer, http://www.partow.net/programming/strtk/index.html

Saygılarımızla gibi bir "özel" bir çözüm için
Marcin

+19

"Hiçbir yol yoktur" "- bir dizeyi ayrıştırmak için" doğru yol "bulunmayan bir dili sevmeniz gerekir ...:( – kralco626

4

Bazı kullanışlı hızlı fonksiyonlar bakabilirsiniz (20/80 kuralını unutmayın) kullanmadığınız 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; 
} 

Örnek:

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

Her türlü akıcı tipte (yüzer vb.) Çalışır. #include <sstream> ve muhtemelen #include <string> gerekir.

+2

Bu çözüm boost :: lexical_cast kullanır – Marcin

+0

Actualla boost :: lexical_cast, orijinal std dize akışlarını kullanmaz, ancak bu işlevlerden biraz daha hızlı yapması gereken bazı tweaked akış sınıfı. kontrol (girişin ekstraksiyon operatörü tarafından tam olarak tüketilip tüketilmediğini kontrol etmek dahil), böylece bu iki fonksiyondan daha güvenlidir. –