2008-12-06 20 views
7

C++ 'da basit bir dizeyi ayrıştırmaya çalışıyorum. Dize, kolon ile bir metin içeren hemen bir boşluk, sonra bir sayı içeren bir metin içerdiğini biliyorum. Dizenin sadece bir kısmını çıkarmak istiyorum. Sadece boşlukta token edemiyorum (sstream ve < < kullanarak) çünkü kolonun önündeki metin içinde boşluk olabilir veya olmayabilir.C++ dilinde bir alt dizgi için std :: string'i nasıl ararsınız?

Bazı örnek dizeleri olabilir:

Toplam disk alanı: 9852465

Boş disk alanı: 6243863

Sektörleri: 4095

ı kullanmak istiyorum standart kütüphane, ancak başka bir çözümünüz varsa bunu da gönderebilirsiniz, çünkü aynı soruya sahip olan kişiler farklı çözümler görmek isteyebilirler.

int value; 
if(sscanf(mystring.c_str(), "%*[^:]:%d", &value) == 1) 
    // parsing succeeded 
else 
    // parsing failed 

Açıklama: Bütünlüğü için

cevap

14
std::string strInput = "Total disk space: 9852465"; 
std::string strNumber = "0"; 
size_t iIndex = strInput.rfind(": "); 
if(iIndex != std::string::npos && strInput.length() >= 2) 
{ 
    strNumber = strInput.substr(iIndex + 2, strInput.length() - iIndex - 2) 
} 
+2

'! = -1' KULLANMAYIN! Bunun yerine '! = String :: npos' kullanın. –

+1

Neden olmasın, Konrad, işe yaramıyor mu, verimsiz mi ??? Akıl yürüten beyinler bilmek ister. – paxdiablo

+0

İyi yakalama Konrad! – BobbyShaftoe

2
const std::string pattern(": "); 
std::string s("Sectors: 4095"); 
size_t num_start = s.find(pattern) + pattern.size(); 
+0

Brian'ın çözümü hataları kontrol ediyor, benimki yok - onunkini kullan :) – orip

+0

Hala sihirli bir numara kullanmaman için +1 veriyorum. :) –

8

, burada C basit bir çözüm var %*[^:] iki nokta üst üste olmadıklarından birçok olası karakterleri okumak diyor ve * atama bastırır . Daha sonra, tamsayı, kolondan ve herhangi bir araya giren beyaz boşluktan sonra okunur.

+0

Teşekkürler, insanlar alternatif çözümler sunduğunda hoşlanıyorum. Eminim bu gelecek C programcılarına yardımcı olacaktır. –

+0

kişisel olarak harika bir şekilde sizin çözümünüzü beğendim Konrads :) bile onlar bir alt dizide arama yapmazlar, temiz bir şekilde nasıl ayrıştırılacağını gösterirler –

4

Sadece alanı simgeleştirir olamaz kolon önünde metin ya da içinde boşluklar olabilir veya olmayabilir, çünkü (sstream ve < < kullanılarak).

Doğru, ama std::getline kullanabilirsiniz:

string not_number; 
int number; 
if (not (getline(cin, not_number, ':') and cin >> number)) { 
    cerr << "No number found." << endl; 
} 
+0

Bu yeni bir satır arar; Bir üçüncü parametre olarak bir sınırlayıcı alan ve bu parametre için ':' iletmek için getline aşırı yüklemesini kullanmak istediniz mi? –

+0

Teşekkürler Adam, Üçüncü argümanı unutmuştum. : -/ –

+0

… ve yine başka bir aptal hata. Yaptığım gibi görünüyor. –

3

Konrads cevaba benzer, ancak istream::ignore kullanarak:

int number; 
std::streamsize max = std::numeric_limits<std::streamsize>::max(); 
if (!(std::cin.ignore(max, ':') >> number)) { 
    std::cerr << "No number found." << std::endl; 
} else { 
    std::cout << "Number found: " << number << std::endl; 
} 
+1

Evet, aslında daha iyi bir cevap. Bununla birlikte, IIRC, bazı platformlarda (muhtemelen imzalı/imzasız uyumsuzluk nedeniyle) 'ihmal' ve 'maks' ile ilgili bazı problemler vardır. Ancak bu bilgiler tarihlendirilebilir. –

+1

Evet, temel olarak işaretlenmiş bir std dosyasında okundu. Aslında sadece baktım, ppl neden akıp gitmediğini merak ettim (-1) :) –

3

kimsenin normal ifadeler belirtilen şaşırdım. Bunlar TR1'in bir parçası olarak eklenmiştir ve Boost'a dahil edilmiştir. Burada, regex'in

typedef std::tr1::match_results<std::string::const_iterator> Results; 

std::tr1::regex re(":[[:space:]]+([[:digit:]]+)", std::tr1::regex::extended); 
std::string  str("Sectors: 4095"); 
Results   res; 

if (std::tr1::regex_search(str, res, re)) { 
    std::cout << "Number found: " << res[1] << std::endl; 
} else { 
    std::cerr << "No number found." << std::endl; 
} 

kullanımıyla ilgili çözüm çok daha fazla işe yaramış gibi gözükmektedir, ancak IMHO'dan daha fazlasını elde edersiniz.

İlgili konular