How to keep reading using cin until a blank line is reached - c++

I am trying to use standard input(cin) to read in inputs until a blank line is hit. I tried many times but still fail to achieve it. Can anyone help me out?
The following is the input format. Note: 1. // are comments 2. Comments can be randomly distributed after the second line in the input. So I also need to clear those comments. Not sure how to do it.3.The first line has to be a single letter. 4.The second line has to be an integer.
A       8      goodgreatamazingwonderfulfantasticterrific//These are some random commentsbrilliantgeniusstackoverflow
The following is what I have right now. I'm trying to use getline but the program just reads in the first two lines(the letter and the number). Then the programs ends. Not sure what is going wrong:
void read() {
vector<string> my_vec;
char my_letter;
cin >> my_letter;
int my_num
cin >> my_num;
string current_word;
while (getline(cin, current_word)) {
if (current_word.empty()) {
break;
}
if (current_word[0] != '/' ) {
my_vec.push_back(current_word);
}
}
}

The extraction cin >> my_num; does not extract the newline (which is whitespace, so the next getline call extracts an empty line.
Alternative ways to solve this:
Always use line-based string extraction and subordinate string streams.
Use std::cin >> my_num >> std::ws to gobble whitespace.
Use std::cin.ignore(1, '\n') to gobble the one newline.
Use a dummy std::getline(std::cin, current_word) call to gobble the one newline.

Related

C++ cin.ignore() works even when used after getline(), but why?

I am teaching an after school club about cin and getline() right now and I know you're suppose to put a cin.ignore() when switching from cin and getline; I also know why we do that, it all makes sense.
However.... A student put cin.ignore() AFTER the getline() call and it still worked as if they put it before getline(), does anyone know why?
What I teach and what I know works.
string answer, line;
cin >> answer;
cin.ignore();
getline(cin, line);
What shouldn't work but does even though cin.ignore is after getline()?
string answer, line;
cin >> answer;
getline(cin, line);
cin.ignore();
Please read carefully how operator>> works, and what ignore() does.
by default, operator>> discards leading whitespace characters before extracting data needed for a value. This can be disabled with std::noskipws.
operator>> for integer types extracts as many characters as possible to interpret them as an integer.
operator>> for a string extracts only non-whitespace characters. Reading stops just before the first whitespace character.
by default, .ignore() discards just a single character.
to trim a line after operator>>, ignore should be used as: .ignore(std::numeric_limits<std::streamsize>::max(), '\n');
This leads to the following cases:
type
input
read effect
remaining input
int
11
11
int
12
12
int
1\n
1
\n
int
1 \n
1
\n
int
13das
13
das
std::string
foo
"foo"
Your first example will fail if line ends with extra spaces.
Your second example may appear to be working if input contains leading whitespace, or other characters which are skipped do not have impact on reading the result (for example: +12 when reading int).

How does cin works in a while loop when the inputs are given in a single line with white spaces?

Consider this small piece of code:
#include <iostream>
#include<stdio.h>
using namespace std;
int main() {
int a;
while(true){
cin>>a;
cout<<a;
}
return 0;
}
Input
1 2 3 5 7 23
Output
125723
How I thought it will run is:
First iteration
1. Reads the first input ie '1' and stops reading further, right after reading the whitespace.
2.Prints the value 1.
Second iteration
1. Again asks for new input
2. Print that in the second line
But that doesn't happen instead it reads the elements we gave after space
First iteration:
Peek at next character in the stream. It's a digit ('1'), so read it.
Peek at next character in the stream. It's not a digit (' '), so don't read it; store 1 in a and return from >>.
(Output 1.)
Second iteration:
Peek at next character in the stream. It's whitespace (' '), so read and ignore it.
Peek at next character in the stream. It's a digit ('2'), so read it.
Peek at next character in the stream. It's not a digit (' '), so don't read it; store 2 in a and return from >>.
(Output 2.)
And so on ...
The point is that >> does not care about lines. cin is one long input stream of characters (some of which may be '\n'). The only thing you can do is read more characters (and then maybe decide that you don't want to do anything with them).
cin is not necessarily connected to a keyboard. The program that started you gets to decide where cin reads from. It can be a file, a network socket, or interactive user input. In the latter case, reading from cin may block until the user types more input, but it will never cause input to just be dropped.
If you want a sane user interface, always read whole lines and process them afterwards:
std::string line;
while (std::getline(std::cin, line)) {
// do stuff with line
}

Switching from formatted to unformatted input in C++

I have an input text file. The first line has two int numbers a and b, and the second line is a string. I want to use formatted input to do file >> a >> b, and then unformatted input to get the characters of the string one by one. In between the two steps, I need to skip over the '\n' character at the end of the first line. I used
while(file.get()<=' ' && !file.eof()); // skip all unprintable chars
if(!file.eof()) file.unget(); // keep the eof sign once triggered
to make the input format more flexible. The user can now separate the numbers a and b from the string using an arbitrary number of empty lines '\n', tab keys '\t', and/or space keys ' ' -- the same freedom he has to separate the numbers a and b. There's even no problem reading in Linux a text file copied from Windows when every end of line now becomes "\r\n".
Is there an ifstream function that does the same thing (skip all chars <=' ' until the next printable char or EOF is reached)? The ignore function does not seem to do that.
Yes, there is: std::ws manipulator. It skips whitespace characters until a non-whitespace is found or end of stream is reached.. It is similar to use of whitespace character in scanf format string.
In fact, it is used by formatted input before actually starting to parse characters.
You can use it like that:
int x;
std::string str;
std::cin >> x >> std::ws;
std::getline(std::cin, str);
//...
//std::vector<int> vec;
for(auto& e: vec) {
std::cin >> e;
}
std::getline(std::cin >> std::ws, str);

Reading Data from a Text File and Ignoring Others

For a small portion of my project, I'm supposed to extract data from a text file using cin which my program will know where to cin from based on command line arguments. My issue is how to extract the four pieces of data and ignore the commas. For example, the .txt file will look like the following
(1,2,3,.)
(2,1,3,#)
(3,1,0,.)
In which case I need to extract the 1, the 2, the 3, and the . for the first line. Then move to the second line. When a blank newline is reached than I can exit the getline() scenario through a while loop.
I know I need to use getline() and I was able to extract the data by using the .at() function of the string generated by getline(). I became confused however when a coordinate such as the 1, the 2, or the 3, could be double digits. When this happened, my previous algorithm didn't work so I feel I'm overthinking things and there should be a simpler way to parse this data.
Thanks!
You can just use the >> operator to a dummy 'char' variable to read in the separators. This assumes you don't care about the 4th token and that it's always a single character:
char ch;
while (ss >> ch)
{
int a,b,c;
ss >> a >> ch >> b >> ch >> c >> ch >> ch >> ch;
}
A simple approach is to use sscanf, pass the string you read from cin to it as the first argument
sscanf(s, "(%d,%d,%d,%c)", &a, &b, &c))
If you want to parse the string from scratch, just focus the pattern.
In this case, the pattern is
'(', number, ',', number, ',', number, ',', char, ')'
So you can locate the three commas, then simply extract three numbers from between them.
A more complicated method is regex.
But C++ doesn't have native support for that (the Boost library does)

How do I know when one is done entering cin with \n? (loop)

From Australian voting problem:
A bot will keep putting information and it can reach 1000 lines.
Example of what he'll enter:
"1 2 3
2 1 3
2 3 1
1 2 3
3 1 2
"
How do I know when he has finished entering information? There is an extra \n at the end and that's my only guess on where to go.
cin doesn't seem to detect \n, but getchar() apparently does. It will however get the \n even after the first line of course, and getting it to work has become rather difficult. How do I accomplish this?
I'd suggest using cin.getline It will get a whole line at a time (ending with \n) and when you get an empty line, you know you're done.
Edit
As suggested by sbi, std::getline is typically a better option for this situation as it utilizes strings rather than char arrays.
std::string line;
while( std::getline(std::cin,line) && !line.empty() ) {
std::istringstream iss(line);
int i1, i2, i3;
iss >> i1 >> i2 >> i3
if( !is ) throw "dammit!"
process_numbers(i1,i2,i3);
}
if( !std::cin.good() && !std::cin.eof() ) throw "dammit!";
Reading input with cin and the extraction operator >> skips whitespace. Instead, read the input line by line and exit when the line is empty.
You could instead read a line at a time, and look for the blank line (then later splitting each non-blank line into its 3 numbers).