C++ 如何使用istringstream提取混合格式

C++ 如何使用istringstream提取混合格式,c++,istringstream,formatted-input,C++,Istringstream,Formatted Input,为什么我的程序不输出: 10 1.546 ,Apple 1 而不是 10 1 <empty space> 10 1. 以下是我的节目: #include <iostream> #include <string> #include <sstream> using namespace std; int main () { string str = "10,1.546,Apple 1"; istringstream stream

为什么我的程序不输出:

10
1.546
,Apple 1
而不是

10
1
<empty space>
10
1.
以下是我的节目:

#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;
}
#包括
#包括
#包括
使用名称空间std;
int main(){
string str=“10,1.546,苹果1”;
istringstream(str);
INTA;
双b;
字符串c,虚拟;
流>>a>>虚拟>>b>>虚拟>>c;

cout您应该执行以下更改:

string str = "10  1.546 Apple 1";

在你的例子中,哑人会得到字符串“1.546,苹果”。因为遇到非数字字符时,它被馈送给变量A。然后,所有的东西都被添加到哑(字符串)中,直到默认分隔符(空间)在IOFiString中达到

< P>,字符串(即C字符串和C++字符串)。几乎没有格式要求。只有在找到空白字符或捕获流的结尾之前,才会将任何和所有字符提取到字符串中。在您的示例中,您使用的字符串旨在消耗重要数据之间的逗号,但您所经历的输出是I jus行为的结果t解释说:
dummy
字符串不仅吃逗号,还吃字符序列的其余部分,直到下一个空白字符

为了避免这种情况,您可以对虚拟变量使用
char
,该变量只有一个字符的空间。如果您希望将
Apple 1
放入字符串中,则需要进行无格式提取,因为格式化提取程序
运算符>>()
只读取到空格。此处使用的适当函数是
std::getline()

在格式化提取之后清除换行也是必要的,这就是为什么我使用
std::ws
来清除前导空格。我还使用
if
语句来包含提取,以判断提取是否成功


任何更顺利的方法都会对我大有帮助

您可以使用流中嵌入的区域设置的
std::ctype
方面将逗号字符的分类设置为空白字符。这将不需要使用伪变量。以下是一个示例:

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
} 
名称空间详细信息
{
枚举选项{添加,删除};
类ctype:public std::ctype
{
私人:
静态掩码*get_表(const std::string&ws,options opt)
{
静态std::向量表(经典_表(),
经典表格()+表格大小);
for(字符c:ws)
{
如果(opt==添加)
表[c]|=空间;
else if(opt==删除)
表[c]&=~空间;
}
返回&表[0];
}
公众:
ctype(const std::string&ws,options opt)
:std::ctype(get_表(ws,opt)){
};
}
类调整w_impl
{
公众:
adjustws_impl(常数std::string&ws,细节::选项选项):
m_ws(ws),
m_opt(opt)
{ }
friend std::istream&operator>>(std::istream&is,
常数调整(安装和维护)
{
const detail::ctype*facet(新的detail::ctype(manip.m_-ws,manip.m_-opt));
如果(!std::has_facet(is.getloc())
{
is.imbue(std::locale(is.getloc(),facet));
}否则
删除刻面;
回报是;
}
私人:
std::字符串m_ws;
细节:选项m_opt;
};
adjustws_impl setws(常量标准::字符串和字符串)
{
返回调整ws_impl(ws,detail::add);
}
adjustws_impl unsetws(常量std::string&ws)
{
返回调整ws_impl(ws,detail::remove);
}
int main()
{
标准:istringstream iss(“10,1.546,苹果1”);
int a;double b;std::string c;
iss>>setws(“,”;//将逗号设置为空白字符
如果((iss>>a>>b)和&std::getline(iss>>std::ws,c))
{
// ...
}
iss>>取消设置(“,”;//删除空白分类
} 

我可以稍微修改一下代码。还没有实现
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;
}
#包括
#包括
#包括
#包括
使用名称空间std;
int main(){
string str=“10,1.546,苹果1”;
istringstream(str);
INTA;
双b;
字符串c;
字符串标记;
while(getline(流,令牌,,)){
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());
}否则{
c=字符串(令牌);
}
}

请允许我提出以下建议

<> P>我不认为它更流畅,因为CI/CUT对话不是“平滑”的,imHo。< /P> 但我认为这可能更接近你想要的

 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;
 }
int main(int,char**)
{
//始终初始化变量
//为您不期望的输入值
int a=-99;
双b=0.0;
std::字符串c(“”);
字符comma1='Z';
char comma2='z';
std::string str=“10,1.546,苹果1”;
std::istringstream ss(str);
ss>>a>>comma1>>b>>comma2;
//最后一个参数中包含默认分隔符
(void)getline(ss,c,'\n');//要通过此默认分隔符,
//指定不同的分隔符

std::cout char dummy将修复它(第二个是吃掉输入)@DieterLücking
string dummy;
d'oh。我像白痴一样盯着代码看,没有看到:)@DieterLücking是的,它已经改进为输出10和1.546,但我需要
Apple 1
,而且什么也没有得到,我现在得到了
Apple
,但仍然没有
Apple 1
。有什么想法吗?@SunilKundal提取停止在
Apple
1
之间。你需要使用
std::getline()
(当然是在清除了新线之后)。你应该解释一下原因。我喜欢这个
#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;
}
 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;
 }