Read newline using stream C++

前端 未结 4 2047
伪装坚强ぢ
伪装坚强ぢ 2021-01-26 18:08

How do I also read a new line using C++ >> operator?

ifstream input(\"doc.txt\".c_str());
vector contents;
while (input >> word) {
    conten         


        
4条回答
  •  抹茶落季
    2021-01-26 18:26

    If you're looking to specifically use operator>> and you don't technically need to use strings specifically, you can simply make a custom class with the behavior you want when it's read in from an istream. It can even be (mostly) a wrapper for a string, with custom behavior when reading initial whitespace.

    class StringAndNewline{
        std::string str_;
        friend std::istream& operator>>(std::istream& in, StringAndNewline& str);
    public:
        StringAndNewline() : str_(){}
        StringAndNewline(std::string str) : str_(str){}
    
        const std::string& str() const noexcept {return str_;}
        std::string release() {return std::move(str_);}
    };
    

    The string read in operator automatically ignores all preceding whitespace to a sequence of non-whitespace characters, as defined by the present locale. This is the behavior you want to change, and as it turns out it's pleasantly simple to do so.

    Disposal of the initial whitespace is commonly preformed by something called a sentry object, which also checks that the stream is valid and sets the stream's failbit if it's at the end of the file. While its default behavior is to consume whitespace until it encounters a non-whitespace character, this is controlled by a flag in its constructor, so we can use that very nice encapsulated stream validity check it offers.

    The string overload of operator>> makes and checks a sentry, then reads until it encounters whitespace, the end of the stream, or a read fails. We can simply ensure that its sentry never encounters whitespace by dealing with it ourselves.

    Thus the ultimate read-in structure for our custom class' custom operator>> will look something like this:

    • make non-whitespace eating sentry
    • check sentry, returning the failed stream if it's invalid
    • deal with whitespace
    • read data into wrapped string
    • return the stream

    Since we're only concerned with the '\n' characters in our whitespace that's simple too: just loop while the stream is valid (if it runs out of space before hitting either of our conditions, it sets failbit like we would want) and exit the loop if one of two conditions are net: we get a newline character, or we get a non-whitespace character. Again, pleasantly simple:

    std::istream& operator>>(std::istream& in, StringAndNewline& str){
        std::istream::sentry sentry{in, true}; // make a sentry that doesn't eat whitespace
        if(!sentry){return in;} // check the sentry
        std::locale
            presentLocale{}; // get the present locale
        char presentChar;
        while(in.get(presentChar)){ // while the stream is valid
            if(presentChar == '\n'){ // if we get a newline
                str.str_ = "\\n"; // set the string to an escaped newline
                break; // exit the loop
            }
            // if we get a non-whitespace character
            else if(!std::isspace(presentChar, presentLocale)){
                in.unget(); // replace the character in the stream
                in >> str.str_; // take advantage of the existing string operator
                break; // done with loop
            }
        }
        return in; // return the istream, whatever state it might be in
    }
    

    Once this is done, we set up an ostream operator for ease of printing:

    std::ostream& operator<<(std::ostream& out, const StringAndNewline& str){
        return out << str.str();
    }
    

    and test our code:

    int main (){
        std::istringstream file(
            "hello\n"
            "world\n"
            "C++ is the best tool"
        );
        StringAndNewline
            wordOrNewline;
        while(file >> wordOrNewline){
            std::cout << wordOrNewline << '\n';
        }
    }
    

    which prints this:

    hello
    \n
    world
    \n
    C++
    is
    the
    best
    tool
    

    just like we wanted! Live on Coliru

    You could even write a string operator if you really wanted to to easily convert the wrapper class to strings, but I'll leave that to you.

提交回复
热议问题