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

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.

Related

C++ CSV Getline

I have one column of floats in a csv file. No column header.
string val;
vector<float> array;
string file = "C:/path/test.csv";
ifstream csv(file);
if (csv.is_open())
{
string line;
getline(csv, line);
while (!csv.eof())
{
getline(csv, val, '\n');
array.push_back(stof(val));
}
csv.close();
}
I want to push the values in the column to vector array. When I use ',' as a delimiter it pushes the first line to the array but the rest of the column gets stuck together and unpushable. If I use '\n' it doesn't return the first line and I get a stof error.
I tried other answers unsuccessfully. What is the correct way to format this here?
test.csv
Your raw test.csv probably looks like this:
1.41286
1.425
1.49214
...
So there are no comma's, and using , as '(line) separator' would read the whole file and only parse the first float (up to the first \n).
Also, the first line is read but never used:
getline(csv, line); // <- first line never used
while (!csv.eof())
{
getline(csv, val, '\n');
array.push_back(stof(val));
}
Since there is only one field you don't have to use a separator and, as already mentioned in the comments, using while(getline(...)) is the right way to do this:
if (csv.is_open())
{
string line;
while (getline(..))
{
array.push_back(stof(val));
}
csv.close();
}

C++: Using getline to input from a text file either skips the first line or messes up the rest

I'm trying to read in from a specially formatted text file to search for specific names, numbers, etc. In this case I want to read the first number, then get the name, then move on to the next line. My problem seems to be with while loop condition for reading through the file line by line. Here is a sample of the txt file format:
5-Jon-4-Vegetable Pot Pie-398-22-31-Tue May 07 15:30:22
8-Robb-9-Pesto Pasta Salad-143-27-22-Tue May 07 15:30:28
1-Ned-4-Vegetable Pot Pie-398-22-31-Tue May 07 15:30:33
I'll show you two solutions I've tried, one that skips the first line in the file and one that doesn't take in the very last line. I've tried the typical while(!iFile.eof()) as a last ditch effort but got nothing.
transactionLog.clear();
transactionLog.seekg(0, std::ios::beg);
std::string currentName, line, tempString1, tempString2;
int restNum, mealNum;
bool nameFound = false;
int mealCount[NUMMEALS];
std::ifstream in("patronlog.txt");
while(getline(in, line))
{
getline(in, tempString1, '-');
getline(in, currentName, '-');
if(currentName == targetName)
{
if(getline(in, tempString2, '-'))
{
mealNum = std::stoi(tempString2);
mealCount[mealNum - 1] += 1;
nameFound = true;
}
}
I believe I understand what's going in this one. The "getline(in, line)" is taking in the first line entirely, and since I'm not using it, it's essentially being skipped. At the very least, it's taking in the first number, followed by the name, and then doing the operations correctly. The following is the modification to the code that I thought would fix this.
while(getline(in, tempString1, '-'))
{
getline(in, currentName, '-');
// same code past here
}
I figured changing the while loop condition to the actual getline of the first item in the text file would work, but now when I look at it through the debugger, on the second loop it sets tempString1 to "Vegetable Pot Pie" rather than the next name on the next line. Ironically though this one does fine on line #1, but not for the rest of the list. Overall I feel like this has gotten me farther from my intended behavior than before.
You need to parse the contents of lines after they are read. You can use a std::istringstream to help you with that.
while(getline(in, line))
{
// At this point, the varible line contains the entire line.
// Use a std::istringstream to parse its contents.
std::istringstream istr(line);
getline(istr, tempString1, '-'); // Use istr, not in.
getline(istr, currentName, '-'); // ditto
...
}

std::getline not producing correct output (c++)

I'm doing a homework assignment in c++ and I could use a little help. I am not understanding why the following code isn't working as I want it. The object of the function I'm creating is to load a file and parse it into keys and values for a map while skipping blank lines and lines where the first character is a hastag. The file I'm reading from is below.
The problem is that my nextToken variable is not being delimited by the '=' character. I mean, when I cout nextToken, it doesn't equal the string before the '=' character. For example, the first two lines of the data file are
# Sample configuration/initialization file
DetailedLog=1
I thought that the code I have should skip all the lines that begin with a hashtag (but it's only skipping the first line) and that nextToken would equal just DetailedLog (as opposed to DetailedLog=1 or just equal to 1).
In my output, some lines with a hashtag are skipped while some are not and I can't understand where cout is printing from since the cout statement I have should print "nextToken: " and then nextToken, but it's printing nextToken then "nextToken: " then what comes after the '=' character from the data file.
Here's my code:
bool loadFile (string filename){
ifstream forIceCream(filename);
string nextToken;
if (forIceCream.is_open()){
while (getline(forIceCream, nextToken, '=')) {
if (nextToken.empty() || nextToken[0] == '#') {
continue;
}
cout << "nextToken: " << nextToken << endl;
}
}
}
Data file reading from:
# Sample configuration/initialization file
DetailedLog=1
RunStatus=1
StatusPort=6090
StatusRefresh=10
Archive=1
LogFile=/tmp/logfile.txt
Version=0.1
ServerName=Unknown
FileServer=0
# IP addresses
PrimaryIP=192.168.0.13
SecondaryIP=192.168.0.10
# Random comment
If the first two lines of your input file are:
# Sample configuration/initialization file
DetailedLog=1
Then, the call
getline(forIceCream, nextToken, '=')
will read everything up to the first = to nextToken. At the end of the line, the value of nextToken will be:
# Sample configuration/initialization file
DetailedLog
See the documentation of std::getline and pay attention to the first overload.
You need to change your strategy for processing the contents of the file a little bit.
Read the contents of the file line by line.
Process each line as you see fit.
Here's an updated version of your function.
bool loadFile (string filename)
{
ifstream forIceCream(filename);
if (forIceCream.is_open())
{
// Read the file line by line.
string line;
while ( getline(forIceCream, line) )
{
// Discard empty lines and lines starting with #.
if (line.empty() || line[0] == '#')
{
continue;
}
// Now process the line using a istringstream.
std::istringstream str(line);
string nextToken;
if ( getline(str, nextToken, '=') )
{
cout << "nextToken: " << nextToken << endl;
}
}
}
}

How do I break out of a getline with a file?

I have code where I am inputting stuff from a file. My txt file looks like this:
file.txt
hello world
...
1 2
The numbers at the bottom are supposed to be read into variables. As for "hello world", it should be picked up by getline. But I don't know how many lines there will be in the txt file so I don't know how to break out of it. Here is my code:
while (getline(file, line))
{
std::cout << line << std::endl;
// ...
}
file >> a >> b; // 1 2
If I was doing this with cin I could just do Ctrl+Z to stop getline loop from running. How do I break out of the while loop at the right time before I get to 1 2?
For each line string line, you can put it into an istringstream iss. And then try to stream it into a and b using iss >> a >> b, if it can be done successfully, it means you enter the right line. Otherwise, you go on checking the next line.
int a, b;
while (getline(file, line))
{
istringstream iss(line);
if (iss >> a >> b)
{
// you are in the right line, and a,b has the values e.g. 1 2
}
}
It should also work for other strings besides "hello world", like "aaa bbb cc" etc. as long as they are not the numbers you are looking for.
P.S.: you can also take use of regex if you use C++11 to check if given line has/matches the pattern you are looking for.
Use a condition, and a break; statement.
E.g.:
while (getline(file, line))
{
std::cout << line << std::endl;
// ...
if(line == "hello world"/){
break;//Exits the loop
}
}
A break statement makes your code exit the most inner loop it's used in. In this case, it exits the while loop.
EDIT:
If you don't want to break on a specific line, then you'll better use regular expression or another mechanism (like std::stringstream) to find a match of the string you're looking for, and capture the part you're interested in. I suggest you take a look at Boost.Regex for this.
The idea is to loop on the lines, i.e. just as you do. As soon as you have a match, you can break (the same way) and capture from the string you're currently reading (which in your code would be in the line variable).
It's not too clear how you determine that you want to break out
of the loop. What is the criterion? If you want to read all
lines but the last, the simplest solution is to simply read all
of the lines into an std::vector<std::string>, and then
process that; you can iterate over a vector until the next to
the last element (which you can't do on a stream). If it's some
pattern your looking to match (say "\\d+\\s+\\d+"), then you
can add this to the condition:
std::string line;
std::regex matchNumbers( "\\d+\\s+\\d+" );
while ( std::getline( file, line ) && ! regex_match( line, matchNumbers ) ) {
// ...
}
std::istringstream numbers( line );
numbers >> a >> b;
And so on.

Why does getline return empty lines if none exist

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.