Skipping expected characters like scanf() with cin

前端 未结 5 816
南笙
南笙 2020-12-03 19:12

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

相关标签:
5条回答
  • 2020-12-03 19:40

    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;
    }
    
    0 讨论(0)
  • 2020-12-03 19:43

    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;
    }
    
    0 讨论(0)
  • 2020-12-03 19:48

    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
    } 
    
    0 讨论(0)
  • 2020-12-03 19:52

    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);
    }
    
    0 讨论(0)
  • 2020-12-03 19:56

    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;
    }
    
    0 讨论(0)
提交回复
热议问题