Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

string line; while (getline(cin, line)) {     // process line } 

or

for (string line; getline(cin, line); ) {     // process line } 

? What is the normal way to do this?

like image 957
cppLearner Avatar asked Oct 14 '09 15:10

cppLearner


People also ask

How do you make a CIN not skip a line?

ignore() to ignore any newlines left from std::cin .

Does CIN work with string?

Inputting a string You can use cin but the cin object will skip any leading white space (spaces, tabs, line breaks), then start reading when it comes to the first non-whitespace character and then stop reading when it comes to the next white space. In other words, it only reads in one word at a time.


1 Answers

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<std::string> lines;  std::copy(std::istream_iterator<line>(std::cin),            std::istream_iterator<line>(),           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<char> {     line_reader(): std::ctype<char>(get_table()) {}     static std::ctype_base::mask const* get_table() {         static std::vector<std::ctype_base::mask>              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<std::string> 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::string>(std::cin),          std::istream_iterator<std::string>(),          std::inserter(lines, lines.end()));      std::copy(lines.begin(), lines.end(),          std::ostream_iterator<std::string>(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).

like image 169
Jerry Coffin Avatar answered Sep 21 '22 15:09

Jerry Coffin