Getline and ifstream? - c++

I'm having an issue with ifstream and getline in conjucntion.
I have a text document:
1020123456
Madison Williams
90
88
79
86
90
And want to assign the name into a students[0].name where students is a struct of type student.
I tried using
inFile >> students[0].id;
getline(inFile, students[0].name);
"cout << students[0].id" yields the ID properly but .name does nothing.
What am I doing wrong here?
And "inFile.getline(students[0].name)" yields errors.

There's a '\n' character there after your numbers. When you inFile >> students[0].id; you read the number, but stop at the '\n' character. Then, when you getline(), there's that '\n' character left in your stream, so it reads an empty string, skips the '\n', and then moves on to the next line (which is where your name is).
You need to skip the '\n' after you read a number and before you call getline(). Calling
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); will ignore what's left in inFile until it meets the '\n' character. So change it to:
inFile >> students[0].id;
inFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
getline(inFile, students[0].name);
// continue as normal...

Related

Extraction Operator reaching EOF on istringstream, behavioral change with int/char/string

So I am doing some simple file I/O in c++ and I notice this behaviour, not sure if I am forgetting something about the extraction operator and chars
Note that the file format in Unix.
ifstream infile("test.txt");
string line;
while(getline(infile, line)){
istringstream iss(line);
**<type>** a;
for(...){
iss >> a;
}
if(iss.eof())
cout << "FAIL" << endl;
}
Say that the input file test.txt looks like this and the <type> of a is int
$ is the newline character (:set line)
100 100 100$
100 100 100$
what I notice is that after the first line is read, EOF is set true;
If the input file is like so, and the <type> of a is char:
a b c$
a b c$
Then the Code behaves perfectly as expected.
From what I understand about File I/O and the extraction operator, the leading spaces are ignored, and the carriage lands on the character after the input is taken out of the input stringstream iss. So in both cases, at the end of each stringstream the carriage lands on the newline character, and it shouldn't be an EOF.
Changing the <type> of a to string had similar failure as <type> = int
BTW failbit is not set,
at the end:
good = 0
fail = 0
eof = 1
getline has extracted and discarded the newline, so line contains 100 100 100, not 100 100 100$, where $ is representing the newline. This means reading all three tokens from the line with a stringstream and the >> operator may reach the EOF and produce the FAIL message.
iss >> a; when a is an int or a string will skip all preceding whitespace and then continue extracting until it reaches a character that can't possibly be part of an int or is whitespace or is the end of the stream. On the third >> from the stream, the end of the stream stops the extraction and the stream's EOF flag is set.
iss >> a; when a is an char will skip all preceding whitespace and then extract exactly one character. In this case the third >> will extract the final character and stop before seeing the end of the stream and without setting the EOF flag.

Read elements from a txt file that are separeted by a character

I'am working on a program where there are first names, last names and a numbers on a file and i need to read that information into my program. My actual problem is that there is people who doesnt have a second name or second last name. To solve the issue I started trying to read from a file until a specific character is found, For example:
Robert, Ford Black,208 //Where Robert is the first name, and Ford Black are his two last names
George Richard, Bradford,508 //Where George Richard are both his first names, and Bradford is his only last
name
I am saving this information in three separeted string, one that will store first and second name, first last and second last name and the third one for the numbers.
I'm trying to only use native libraries from c++.
I've been reading that getline(a,b,c) and IStringStream can actually solve my problem but I don't know how to correctly implement it
It's just a matter of using std::getline with a delimiter character to read out of the string stream. See a simplified example (no error checking) below:
for (std::string line; std::getline(std::cin, line); )
{
std::string firstName, lastName;
std::istringstream iss(line);
std::getline(iss, firstName, ','); // A comma delimits end-of-input
iss >> std::ws; // Skip over any whitespace characters
std::getline(iss, lastName); // Read remaining line
std::cout << "First Name: " << firstName << std::endl;
std::cout << "Last Name: " << lastName << std::endl;
}
Note the line iss >> std::ws; using std::ws from <iomanip> is there to eat up extra whitespace characters (which appear after your comma, in your example).
I'm assuming the C++ line comments in the input are only an annotation for this question, and not part of the actual input.
#include<bits/stdc++.h>
using namespace std;
int main()
{
ifstream myfile("files.txt");
string fullname;
while(getline(myfile,fullname,'/')) break; //here im reading till the first / is acquired and the entire string is stored in "fullname"
string firstname,lastname;
size_t pos=fullname.find(',');
firstname=fullname.substr(0,pos); //store the firstname
lastname=fullname.substr(pos+1);// storee the lastname
cout<<firstname<<" "<<lastname;
}
As the question posed was to read names im assuming before the digit if there were a " / " you can read upto the first occurance of /. this will give you the fullname. Then using the substr on the fullname and find the occurance of a comma if at all it exists. All the characters to the left of position of comma will form your first name and the rest on the right of the position of comma will form the lastname.

C++ if statement not parsing whitespace

My if statement in a c++ console application is not working:
string line;
cin >> line;
if (line == "a b"){
cout << "lalala";
}
When I type "a b" nothing happens.
if i use if (line == "ab") and type ab it works.
std::cin reads delimited by white-space. So when you read cin >> line you are only reading "a" from "a b". Use std::getline(std::cin, line) to read the entire line, including white-space (not '\n').
BTW, you could have easily found this problem by looking at your variables with a debugger, or by printing it. Debug your code before posting questions.
NOTE: By std::cin I mean the operator>>, which has many overloads, as non-members and istream members. The overload that takes a std::string reads delimited by white-space.
Because the reading will end till the whitespace, that means line will be "a" here.
See operator>>(std::basic_string)
until one of the following conditions becomes true:
std::isspace(c,is.getloc()) is true for the next character c in is (this whitespace character remains in the input stream).

Reading in a file by int, then words

I have a text file that resembles
1 \t words words words words
2 \t words words words words
where the # is the line #, followed by a tab, then followed by random words
I need to read in the int, store it, then skip the \t, and read in each word individually while keeping track of that words position.
I was hoping I could it with getline(file, word, ' '), and a counter but that grabs my first word as 1 \t words.
Any help or suggestions would be much appreciated.
use stringstream and getline,
getline(file, line);
std::stringstream ssline(line);
int num;
ssline >> num;
std::string word;
while(ssline >> word){
// do whatever you want.
}
Assuming that you can't say how many words there are on a line, then the simple answer is to do it in two steps.
Read a whole line into a string with getline
Place that string into a std::istringstream and read the line number and following words from the std::istringstream
then repeat from step 1

String vectors not working as expected with newline and iterators? (C++)

I have a text file made of 3 lines:
Line 1
Line 3
(Line 1, a blank line, and Line 3)
vector<string> text;
vector<string>::iterator it;
ifstream file("test.txt");
string str;
while (getline(file, str))
{
if (str.length() == 0)
str = "\n";
// since getline discards the newline character, replacing blank strings with newline
text.push_back(str);
} // while
for (it=text.begin(); it < text.end(); it++)
cout << (*it);
Prints out:
Line 1
Line 3
I'm not sure why the string with only a newline was not printed out. Any help would be appreciated. Thanks.
Wasn't? Actually, it was! The reason you have a newline after Line 1 is exactly that empty string with newline in it and nothing else. If not for that second line, you'd see Line 1Line 3 as output. (You said it yourself: getline discards newline characters.)
Apparently, the way I understand your intent, you were supposed to implement your output cycle as follows
for (it = text.begin(); it < text.end(); it++)
cout << *it << endl;
That way you add a newline after each string during output. But if so, then you don't need to manually add a \n character to empty strings during reading.
In other words, decide what is it you want to do. At this time it is not clear.
If you want to restore the discarded
newline characters during reading,
you have to do it for all lines,
not just for empty ones.
If you want to add the newline
characters during output, you don't
need to explictly push them into the
read lines at all.
In fact, it is a rather strange idea to literally push the newline characters into your strings. What for? Since you already read and store your text line-by-line, the newline characters can be implied. I.e. you can do the printing as I do it above (with endl), and everything will look as expected.
I think the simple answer here, is that getline() strips the trailing newline whether or not there is content in the string. So the three reads you do are as follows:
"Line 1"
""
"Line 3"
which you transform into:
"Line 1"
"\n"
"Line 3"
which when printed is:
Line 1
Line 3
I'd use something like this:
std::vector<std::string> text;
std::string str;
while (std::getline(infile, str))
text.push_back(str);
std::copy(text.begin(), text.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
You're adding complexity that stops your code from working.