Skipping expected characters like scanf() with cin

坚强是说给别人听的谎言 提交于 2019-11-27 06:16:07

问题


How to achieve scanf("%d # %d",&a,&b);sort of effect with cin in C++ ?


回答1:


You could create your own stream manipulator. It is fairly easy.

#include <ios>
#include <iostream>
using namespace std;

// skips the number of characters equal to the length of given text
// does not check whether the skipped characters are the same as it
struct skip
{
    const char * text;
    skip(const char * text) : text(text) {}
};

std::istream & operator >> (std::istream & stream, const skip & x)
{
    ios_base::fmtflags f = stream.flags();
    stream >> noskipws;

    char c;
    const char * text = x.text;
    while (stream && *text++)
        stream >> c;

    stream.flags(f);
    return stream;
}

int main()
{
    int a, b;
    cin >> a >> skip(" # ") >> b;
    cout << a << ", " << b << endl;
    return 0;
}



回答2:


You can skip the # by extracting it into a character:

std::istringstream iss("10 # 20");

int main()
{
   int a, b; char hash;
   iss >> a >> hash >> b;

   assert(a == 10 && b == 20);
}



回答3:


There isn't a direct function inside the istream class that mimics it, unfortunately. There are functions that you might be able to use to manipulate the stream and get the correct input, but I'm not familiar with how they work so I couldn't tell you how.

My best suggestion on how I would personally do it is to use getline() to put the input into a string and then from there I would do a few checks to see if it matches the format. So in your case I would grab the first substring up until the first space, make sure it's a valid decimal, check to make sure the pound sign ('#') is in the correct spot, then grab the ending number to make sure it's valid. If any one of those three objects are incorrect I would set some boolean variable to false to kick out or return or something to indicate that the input was invalid and not the correct format.

Pseudo Code:

...

getline(cin,myStr);

while(!formatCheck(myStr))
{
    cout<<"Not valid format for input";
    getline(cin,myStr);
}

...

bool formatCheck(string str)
{
    string firstPart=str.subString(0,firstSpaceLocation);
    string middle=str[firstSpaceLocation+1];
    string lastPart=str.subString(firstSpaceLocation+3,end);

    if(first part not a valid number || middle!="#" || last part not a valid number)
    {
        return false;
    }

    return true;
}



回答4:


Here's another way. You can classify # as a whitespace character through the std::ctype<char> facet imbued in the locale:

#include <iostream>
#include <sstream>
#include <vector>

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)
    {
        is.imbue(std::locale(is.getloc(),
                             new detail::ctype(manip.m_ws, manip.m_opt)));
        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 # 20");
    int a, b;

    iss >> setws("#");
    iss >> a >> b;

    iss >> unsetws("#");
    std::cout << a << ' ' << b; // 10 20
} 



回答5:


You can skip the #, or any single character, by using std::istream::ignore

std::istringstream sstr("1024 # 768");

int main()
{
   int a, b;
   sstr >> a; 
   sstr.ignore(256,'#');   // ignore until hash character
   sstr >> b;
   std::cout << "a: " << a << " b: " << b << std::endl;
}


来源:https://stackoverflow.com/questions/21764826/skipping-expected-characters-like-scanf-with-cin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!