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?
ignore() to ignore any newlines left from std::cin .
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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With