Why does getline return empty lines if none exist - c++

I have a file containing the following lines:
5556
0 bla.dxf
1 blub.dxf
2 buzz.dxf
The numbers and text are seperated by a singular tab each, there is no whitespace character after 5556. The following code is used for parsing.
int main(int, char**){
std::ifstream file("test.bld");
std::string buildingName;
file >> buildingName;
std::cout << buildingName << std::endl;
std::string buf;
while(getline(file, buf)) {
if(buf.empty()){std::cout << "String was empty"<<std::endl;}
else std::cout << buf << std::endl;
}
return 0;
}
When I parse the file I get an empty line although there obviously is none.
The output reads as follows:
5556
String was empty
0 bla.dxf
1 blub.dxf
2 buzz.dxf
This is only a minimal example. The whole file and the parser is more complex and I would very much like to use direct parsing for the first element and getline for the rest. What am I misunderstanding about line parsing with getline and how do I avoid getting empty lines?

operator>>(istream, string) reads up to but not including the first whitespace character after the extracted token.
To skip the rest of the line after extracting a token, you can either use
std::cin >> std::ws;
(if you know that there is only a newline remaining), or
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
to skip to the end of the line regardless.

I'm assuming because
file >> buildingName;
doesn't move the cursor to the next line, but leaves it at the end of the current line. So when you call getline, you'll read an empty string and then move to the next.

Related

Deleting from a certain point in a file to the end of the line?

I'm having some trouble with detecting two '//' as a char and then deleting from the first '/' till the end of the line (im guessing /n comes into use here).
{
ifstream infile;
char comment = '//';
infile.open("test3.cpp");
if (!infile)
{
cout << "Can't open input file\n";
exit(1);
}
char line;
while (!infile.eof())
{
infile.get(line);
if (line == comment)
{
cout << "found it" << endl;
}
}
return 0;
}
In the test3.cpp file there are three comments, so 3 lots of '//'. But I can't detect the double slash and can only detect a single / which will affect other parts of the c++ file as I only want to delete from the beginning of a comment to the end of the line?
I'm having some trouble with detecting two '//' as a char
That's because // is not a character. It is a sequence of two characters. A sequence of characters is known as a string. You can make string literals with double quotation marks: "//".
A simple solution is to compare the current input character from the stream to the first character of the string "//" which is '/'. If it matches, then compare the next character from the stream with the second character in the string that is searched for. If you find two '/' in a row, you have your match. Or you could be smart and read the entire line into a std::string and use the member functions to find it.
Also:
while (!infile.eof())
{
infile.get(line);
// using line without testing eof- and badbit
This piece of code is wrong. You test for eofbit before reading the stream and process the input.
And your choice of name for the line variable is a bit confusing since it doesn't contain the entire. line but just one character.

Cin from stdin when it his the end of a line

I have a file for example
M
4
2
//comments
.#..
It is given to the program via stdin. I can't use fstream, just iostream.
If I want to read the whole thing character by character could I do?
char first_letter, first_num, second_num;
cin >> first_letter;
cin >> first_num;
cin >> second_num;
Or would the end of the line mess up cin? As in, does cin know after it reads M for first_letter, that it needs to go to the end line?
Secondly I dont want to read the comment lines. My plan is that if I see a / I will use getline to "trash" the line then move to the . # . . and store those in my array. Would that be the best way to do that?
Firstly, streams skip whitespace (space, tabs, newlines) by default, so that part is easy.
Now, concerning the comment lines, this is a bit more complicated. You can use std::getline() to read one line. This will store the line in a string and discard the trailing newline. However, if you e.g. read the first letter in your code above, the newline remains in the stream, so getline() will read an empty string. In short, don't mix line-based and token-based input.
In practice, you read a line and either parse the it manually or you create a stream for that:
while(getline(in, line)) {
if(line.empty()) continue; // empty line
if(line[0] == '#') continue; // comment line
// parse line
std::stringstream s(line);
char c;
s >> c;
}

ifstream get line change output from char to string

C++ ifstream get line change getline output from char to string
I got a text file.. so i read it and i do something like
char data[50];
readFile.open(filename.c_str());
while(readFile.good())
{
readFile.getline(data,50,',');
cout << data << endl;
}
My question is instead of creating a char with size 50 by the variable name data, can i get the getline to a string instead something like
string myData;
readFile.getline(myData,',');
My text file is something like this
Line2D, [3,2]
Line3D, [7,2,3]
I tried and the compiler say..
no matching function for getline(std::string&,char)
so is it possible to still break by delimiter, assign value to a string instead of a char.
Updates:
Using
while (std::getline(readFile, line))
{
std::cout << line << std::endl;
}
IT read line by line, but i wanna break the string into several delimiter, originally if using char i will specify the delimiter as the 3rd element which is
readFile.getline(data,50,',');
how do i do with string if i break /explode with delimiter comma , the one above. in line by line
Use std::getline():
std::string line;
while (std::getline(readFile, line, ','))
{
std::cout << line << std::endl;
}
Always check the result of read operations immediately otherwise the code will attempt to process the result of a failed read, as is the case with the posted code.
Though it is possible to specify a different delimiter in getline() it could mistakenly process two invalid lines as a single valid line. Recommend retrieving each line in full and then split the line. A useful utility for splitting lines is boost::split().

Missing line of data using Getline with Ifstream

Ok so this is killing me at the moment cause its such a simple part of my program that just doesn't want to work. I'm reading data from a textfile to use in a GA.
The first getline() works perfectly, but the second one doesn't want to write any data into my string. When i cout the string it doesn't show anything.
Here is the code:
ifstream inFile;
inFile.open(fname.c_str());
char pop[20], mut[20];
inFile.getline(pop,20);
cout << pop;
inFile.getline(mut,20);
cout << mut; //this outputs nothing
Thanks for any help in advance.
A sample form my file:
there is no line between them mutation is the line straight after population
Population size: 30
Mutation: 20
Your file's first line is 20 characters long (19+new line) but pop[20] can only contain 19 (because the last one is reserved for the null terminator '\0').
When istream::getline stops because it has extracted 20-1 characters, it doesn't discard the new line delimiter (because it was never read). So the next getline just reads the end of the first line, discarding the new line.
That's why you get nothing in the second string.
Your problem is that the length of your input line exceeds the length of the buffer which must hold it.
The solution is to not use character arrays. This is C++, use std::string!
std::ifstream inFile;
inFile.open(fname.c_str());
std::string pop;
std::getline(inFile, pop);
cout << pop << "\n";
std::string mut;
std::getline(inFile, mut);
cout << mut << "\n";
I think you need to find out what the problem is. Add error checking code to your getline calls, refactor the (simple) code into a (simple) function, with a (simple) unittest. Possibly, your second line is longer than the assumed 20 characters (null-term included!).
For an idea of what I mean, take a look at this snippet.
try something like
while (getline(in,line,'\n')){
//do something with line
}
or try something like
string text;
string temp;
ifstream file;
file.open ("test_text.txt");
while (!file.eof())
{
getline (file, temp);
text.append (temp); // Added this line
}

trying to read a text file data into an array to be manipulated then spit back out

My aim is to take the data from the file, split it up and place them into an array for future modification.
The is what the data looks like:
course1-Maths|course1-3215|number-3|professor-Mark
sam|scott|12|H|3.4|1/11/1991|3/15/2012
john|rummer|12|A|3|1/11/1982|7/15/2004
sammy|brown|12|C|2.4|1/11/1991|4/12/2006
end_Roster1|
I want to take maths, 3215, 3 and Mark and put into an array,
then sam scott 12 H 3.4 1/11/1991 3/15/2012.
This is what I have so far:
infile.open("file.txt", fstream::in | fstream::out | fstream::app);
while(!infile.eof())
{
while ( getline(infile, line, '-') )
{
if ( getline(infile, line, '|') )
{
r = new data;
r->setRcourse_name(line);
r->setRcourse_code(3);//error not a string
r->setRcredit(3);//error not a string pre filled
r->setRinstructor(line);
cout << line << endl;
}
}
}
Then I tried to view it nothing is stored.
Firstly line 1 is very different to the remaining lines so you need a different parsing algorithm for them. Something like:
bool first = true;
while(!infile.eof())
{
if (first)
{
// read header line
first = false;
}
else
{
// read lines 2..n
}
}
Reading lines 2..n can be handled by making a stringstream for each line, then passing that in to another getline using '|' as a delimeter, to get each token (sam, scott, 12, H, 3.4, 1/11/1991, 3/15/2012)
if (getline(infile, line, '\n'))
{
stringstream ssline(line);
string token;
while (getline(ssline, token, '|'))
vector.push_back(token);
}
Reading the header line takes the exact same concept one step further where each token is then further parsed with another getline with '-' as a delimiter. You'll ignore each time the first tokens (course1, course1, number, professor) and use the second tokens (Maths, 3215, 3, Mark).
You are completely ignoring the line that you get inside the condition of the nested while loop. You should call getline from a single spot in your while loop, and then examine its content using a sequence of if-then-else conditions.