How do I iterate over cin line by line in C++?

后端 未结 4 751
别跟我提以往
别跟我提以往 2020-11-22 09:53

I want to iterate over std::cin, line by line, addressing each line as a std::string. Which is better:

string line;
while (getline         


        
4条回答
  •  逝去的感伤
    2020-11-22 10:23

    Since UncleBen brought up his LineInputIterator, I thought I'd add a couple more alternative methods. First up, a really simple class that acts as a string proxy:

    class line {
        std::string data;
    public:
        friend std::istream &operator>>(std::istream &is, line &l) {
            std::getline(is, l.data);
            return is;
        }
        operator std::string() const { return data; }    
    };
    

    With this, you'd still read using a normal istream_iterator. For example, to read all the lines in a file into a vector of strings, you could use something like:

    std::vector lines;
    
    std::copy(std::istream_iterator(std::cin), 
              std::istream_iterator(),
              std::back_inserter(lines));
    

    The crucial point is that when you're reading something, you specify a line -- but otherwise, you just have strings.

    Another possibility uses a part of the standard library most people barely even know exists, not to mention being of much real use. When you read a string using operator>>, the stream returns a string of characters up to whatever that stream's locale says is a white space character. Especially if you're doing a lot of work that's all line-oriented, it can be convenient to create a locale with a ctype facet that only classifies new-line as white-space:

    struct line_reader: std::ctype {
        line_reader(): std::ctype(get_table()) {}
        static std::ctype_base::mask const* get_table() {
            static std::vector 
                rc(table_size, std::ctype_base::mask());
    
            rc['\n'] = std::ctype_base::space;
            return &rc[0];
        }
    };  
    

    To use this, you imbue the stream you're going to read from with a locale using that facet, then just read strings normally, and operator>> for a string always reads a whole line. For example, if we wanted to read in lines, and write out unique lines in sorted order, we could use code like this:

    int main() {
        std::set lines;
    
        // Tell the stream to use our facet, so only '\n' is treated as a space.
        std::cin.imbue(std::locale(std::locale(), new line_reader()));
    
        std::copy(std::istream_iterator(std::cin), 
            std::istream_iterator(), 
            std::inserter(lines, lines.end()));
    
        std::copy(lines.begin(), lines.end(), 
            std::ostream_iterator(std::cout, "\n"));
        return 0;
    }
    

    Keep in mind that this affects all input from the stream. Using this pretty much rules out mixing line-oriented input with other input (e.g. reading a number from the stream using stream>>my_integer would normally fail).

提交回复
热议问题