2014-02-16 31 views
3

提取混合格式爲什麼我的程序不輸出:如何使用istringstream

10 
1.546 
,Apple 1 

代替

10 
1 
<empty space> 

這裏是我的程序:

#include <iostream> 
#include <string> 
#include <sstream> 

using namespace std; 

int main() { 
    string str = "10,1.546,Apple 1"; 
    istringstream stream (str); 
    int a; 
    double b; 
    string c, dummy; 
    stream >> a >> dummy >> b >> dummy >> c; 
    cout << a << endl; 
    cout << b << endl; 
    cout << c << endl; 
    return 0; 
} 

基本上我試圖解析用逗號分隔的字符串,任何更平滑的方法都可以幫助我。

+5

字符啞將修復它(第二個是吃了輸入) –

+0

@DieterLücking'字符串假人;'德哦。我盯着像白癡一樣的代碼,並沒有看到它:) – jrok

+0

@DieterLücking是的,它已經改進爲輸出10和1.546,但我需要'蘋果1',並沒有得到任何東西,我現在正在'Apple'但仍然不是「Apple 1」。有任何想法嗎? –

回答

4

在輸入輸出流,字符串(意思是兩個C字符串和C++字符串)幾乎沒有任何的格式要求。任何和所有字符被提取爲一個字符串僅直到一個空白字符被發現,或直至流的末尾被捕獲。在你的榜樣,你使用意在吃起來的重要數據之間的逗號的字符串,但您所遇到的輸出是我剛纔解釋的行爲的結果是:dummy字符串不只是吃了逗號,但也字符序列的其餘部分直到下一個空白字符。

爲了避免出現這種情況,您可以使用char作爲虛擬變量,其中只有一個字符的空間。如果你正在尋找把Apple 1成一個字符串,你需要一個格式化提取,因爲格式化提取operator>>()只讀取,直到空白。在這裏使用相應的功能是std::getline()

string c; 
char dummy; 

if ((stream >> a >> dummy >> b >> dummy) && 
    std::getline(stream >> std::ws, s)) 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
{ 

} 

清除換行後的格式化的提取也是必要的,這就是爲什麼我用std::ws清除前導空格。我還使用了if語句包含以判斷它成功與否的提取。


任何平滑的方式做到這一點會幫助我極大。

您可以使用std::ctype<char>面流中充滿語言環境的逗號字符的類型設置爲空白字符。這將使得不需要使用虛擬變量。這裏有一個例子:

namespace detail 
{ 
    enum options { add, remove }; 

    class ctype : public std::ctype<char> 
    { 
    private: 
     static mask* get_table(const std::string& ws, options opt) 
     { 
      static std::vector<mask> table(classic_table(), 
              classic_table() + table_size); 
      for (char c : ws) 
      { 
       if (opt == add) 
        table[c] |= space; 
       else if (opt == remove) 
        table[c] &= ~space; 
      } 
      return &table[0]; 
     } 
    public: 
     ctype(const std::string& ws, options opt) 
      : std::ctype<char>(get_table(ws, opt)) { } 
    }; 
} 

class adjustws_impl 
{ 
public: 
    adjustws_impl(const std::string& ws, detail::options opt) : 
     m_ws(ws), 
     m_opt(opt) 
    { } 

    friend std::istream& operator>>(std::istream& is, 
            const adjustws_impl& manip) 
    { 
     const detail::ctype* facet(new detail::ctype(manip.m_ws, manip.m_opt)); 

     if (!std::has_facet<detail::ctype>(is.getloc()) 
     { 
      is.imbue(std::locale(is.getloc(), facet)); 
     } else 
      delete facet; 

     return is; 
    } 
private: 
    std::string m_ws; 
    detail::options m_opt; 
}; 

adjustws_impl setws(const std::string& ws) 
{ 
    return adjustws_impl(ws, detail::add); 
} 

adjustws_impl unsetws(const std::string& ws) 
{ 
    return adjustws_impl(ws, detail::remove); 
} 

int main() 
{ 
    std::istringstream iss("10,1.546,Apple 1"); 
    int a; double b; std::string c; 

    iss >> setws(","); // set comma to a whitespace character 

    if ((iss >> a >> b) && std::getline(iss >> std::ws, c)) 
    { 
     // ... 
    } 

    iss >> unsetws(","); // remove the whitespace classification 
} 
0

你應該做以下修改:

string str = "10 1.546 Apple 1"; 

而且

stream >> a >> b >> dummy >> c; 

在你的榜樣,假就已經得到了字符串 「1.546,蘋果」。因爲直到遇到一個非數字的字符,它會被送到變量a。一切都被添加到模型(一個字符串),直到默認的分隔符(空格)後達到

+0

你應該解釋爲什麼。 – jrok

+2

重點是保持格式一致。 – 0x499602D2

+0

@jrok解釋。 –

0

我可以設法改變我的代碼。還沒有實施0x499602D2方法,但這是對我有用的。

#include <iostream> 
#include <string> 
#include <cstdlib> 
#include <sstream> 

using namespace std; 

int main() { 
    string str = "10,1.546,Apple 1"; 
    istringstream stream (str); 
    int a; 
    double b; 
    string c; 
    string token; 
    while (getline (stream, token, ',')) { 
     if (token.find (".") == string::npos && token.find (" ") == string::npos) { 
      a = atoi (token.c_str()); 
     } else if (token.find (".") != string::npos) { 
      b = atof (token.c_str()); 
     } else { 
      c = string (token); 
     } 
    } 
    cout << a << endl; 
    cout << b << endl; 
    cout << c << endl; 
    return 0; 
} 
7

請允許我建議以下幾點。

我不認爲它'更流暢',因爲cin/cout對話不是'流暢',恕我直言。

但我認爲這可能更接近你想要的。

int main (int, char**) 
{ 
    // always initialize your variables 
    // to value you would not expect from input   
    int   a = -99; 
    double   b = 0.0; 
    std::string c(""); 
    char comma1 = 'Z'; 
    char comma2 = 'z'; 

    std::string str = "10,1.546,Apple 1"; 
    std::istringstream ss(str); 

    ss >> a >> comma1 >> b >> comma2; 

    // the last parameter has the default delimiter in it 
    (void)getline(ss, c, '\n'); // to get past this default delimiter, 
           // specify a different delimiter 

    std::cout << std::endl; 
    std::cout << a << " '" << comma1 << "' " << std::endl; 
    std::cout << b << " '" << comma2 << "' " << std::endl; 
    std::cout << c << std::endl; 

    return 0; 
} 

結果:(當然,你不必做的逗號東西。)

10 ''
1.546 ''
蘋果1

+0

我喜歡這種方法..更簡單。謝謝道格拉斯。 –