2014-02-16 32 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

我喜欢这种方法..更简单。谢谢道格拉斯。 –