So I have a .txt file I'm supposed to be reading information in from and displaying in a neat little table. Here's a snippet of the .txt files contents
in the format
Farm name, item count, item, price, total price
Collins Farm, 43900 tomatoes 0.67 29413
Bart Smith Farms, 34910 cassavas 0.99 34560.9
Allen Farms, 117 coconuts 0.54 63.18
etc...
It should print out in the console as
Collins Farm (some spaces here) 43900 items contributed totaling $29413.00
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
using namespace std;
int addLine(int);
int main()
{
using std::ifstream;
ifstream myFile;
myFile.open("ASSGN6-B.txt");
string farmName;
int itemCount;
string itemName;
double itemPrice;
double totalPrice;
if (!myFile)
{
cout << "File open failed!" << endl;
}
else
{
cout << "\t\t\t=========================================================" << endl;
cout << "\t\t\t= FARMER'S MARKET INVENTORY =" << endl;
cout << "\t\t\t=========================================================" << endl;
while (myFile.good())
{
getline (myFile, farmName);
getline (myFile, itemName);
myFile >> itemName >> itemPrice >> totalPrice;
cout << farmName << " " << itemCount << " items contributed totaling $" << totalPrice << endl;
}
}
myFile.close();
return 0;
}
This is what I've been messing with trying to figure out how this input stuff works. I guess what I really don't get is how it's supposed to know which item is which. I previously thought it just read in a line at a time only but theres's gotta be a way to separate the items even on the same line and print them all separately in the console.
Also, some farm names appear twice in the .txt file and I'm supposed to combine their data into one line if it's a duplicate. Help with this would be appreciated too.
Thanks.
First piece of advice:
Don't use
while (myFile.good()) { ... }
You need to make sure that the data you expect to read are indeed read successfully.
See Why is iostream::eof inside a loop condition considered wrong? to understand why.
Coming to the other problems...
The line
getline (myFile, farmName);
will read an entire line to farmName. That's not what you want. You want to read everything up to the comma (,) character. std::getline has such an option. Use
getline (myFile, farmName, ',');
It's not clear what you were hoping to accomplish by
getline (myFile, itemName);
That line can be removed.
Looking at the sample data, all you need is
myFile >> itemCount >> itemName >> itemPrice >> totalPrice;
to read rest of the data.
However, after you read them, make sure to ignore the everything in that line. You can use istream::ignore for that.
Here's my suggestion.
while ( getline(myFile, farmName, ',') &&
(myFile >> itemCount >> itemName >> itemPrice >> totalPrice) )
{
cout << farmName << " " << itemCount << " items contributed totaling $" << totalPrice << endl;
// Ignore rest of the line
myFile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
Make sure to add
#include <limits>
to be able to use std::numeric_limits.
I think you should try to do more research to understand file operations in c++, but I noticed a few things with your code:
getline(myFile, farmName);
This line will take the entire line of the file it's reading and store it into farmName. It basically reads the line until it finds the end of line character. I think your intention was for the line to read until the comma for the farm name, thus you would use:
getline(myFile, farmName, ',');
The third parameter is an optional delimiting character that tells getline what character to look for to stop reading at.
The next lines that I noticed are:
getline(myFile, itemName);
myFile >> itemName >> itemPrice >> totalPrice;
Why are you reading data into itemName twice? I think you meant to read into itemCount first before itemName by the looks of your file format, thus you should eliminate the first line shown above and just have:
myFile >> itemCount >> itemName >> itemPrice >> totalPrice;
In terms of adding to the existing data if the farm name appears more than once, your current code overwrites the data from each line after printing and continuing to the next iteration of the while loop. Thus, you would have to redesign your code to save previous values from farms and check if the farm appears more than once and determine what to do from there.
Could use regex:
std::string line;
std::regex r{R"(([^,]*), ?([^ ]*) ([^ ]*) ([^ ]*) (\d*.?\d*))"};
std::smatch m;
while(getline(myFile, line)){
std::regex_match(line, m, r);
std::string farmName { m[1] };
int itemCount {std::stoi(m[2])};
std::string itemName { m[3] };
double itemPrice {std::stod(m[4])};
double totalPrice {std::stod(m[5])};
std::cout << farmName << " " << itemCount << " items contributed totaling $" << totalPrice << std::endl;
}
Related
I have created a .txt file which a sample would be like this:
Item 1 $1.00
Item # $2.00
Item & $3.50
Item ( $0.30
If I want to ask the user to input the item they want and find the price, how can I do that?
I have tried using .find() to solve the problem, but it didn't work because array cannot use .find().
I'm new to C++, please explain.
#include <array>
#include <string>
#include <fstream>
using namespace std;
string product;
ifstream file("Item.txt");
int main(){
cout << "Enter item you want" << endl;
cin >> product;
file.open("Item.txt", fstream::ate);
findItem.find((file.begin(),file.end(), product) + 1);
cout << findItem << endl;
file.close();
}
Here's a sample code fragment to search your file:
std::string text_line;
while (std::getline(file, text_line))
{
std::string text_item;
std::string item_name;
char dollar_sign;
double price;
std::istringstream text_stream(text_line);
text_stream >> text_item >> item_name >> dollar_sign >> price;
if (product == item_name)
{
std::cout << "Found item\n";
break;
}
}
The usual method is to create a class that models the input line, then overload operator>> to read from a stream.
Notes: 1) commas separating fields would make reading easier; 2) Remove the dollar sign to make reading easier.
I am trying to write a program in C++ that emulates a college enrollment system, where the student enters their ID, and the program searches a text file for their information, and loads a struct based on the text file. I have gotten to a point where I am having trouble getting their enrolled courses into the struct's array. Using the getline function, using the ',' as the delim will also carry over the next line until the next comma. What would be the correct algorithm for this?
This is the file setup that contains fake student information:
918273645,Steve,Albright,ITCS2530,MATH210,ENG140
123456789,Kim,Murphy,ITCS2530,MATH101
213456789,Dean,Bowers,ITCS2530,ENG140
219834765,Jerry,Clark,MGMT201,MATH210
(Bullets added for layout; not in the file)
For example, the user enters "123456789" for their ID, and Kim Murphy's information is then read. Upon the first iteration of getline, "ITCS2530" is read and put into the variable, and is then loaded into the struct; no problem there. However, the last course in the list has the newline character before the next comma, so the next iteration reads "MATH101/nl213456789" and puts the entire string into the variable and tries to load that into the struct.
The first column is their ID, then their First name, last name, and then their currently-enrolled courses after that. Notice that the number of enrolled courses can vary.
Here is the code that I am currently working on:
student login()
{
string ID;
student newStudent;
string enrolled;
int i = 0;
while (true)
{
cout << "Enter Student ID: ";
cin >> newStudent.ID;
cout << endl;
if (newStudent.ID.length() == 9)
break;
else
cout << "That ID is invalid - IDs are 9 digits" << endl;
}
ifstream inFile;
ofstream outFile;
inFile.open("registration.txt");
if (inFile.is_open())
//Check if file is open
{
while (!inFile.eof())
//While not at end of file
{
getline(inFile, ID, ',');
//Search for ID
if (ID == newStudent.ID)
{
getline(inFile, newStudent.fName, ',');
//Assign fName and lName
getline(inFile, newStudent.lName, ',');
while (enrolled != "\n")
{
getline(inFile, enrolled, ',');
if (enrolled == "\n")
{
cout << "Not currently enrolled in a class." << endl;
}
else
{
newStudent.courses[i] = enrolled;
i++;
}
}
cout << newStudent.lName << ", Welcome to the MCC Enrollment System!" << endl;
for (i = 0; i <= NUM_OF_COURSES; i++)
{
cout << "Enrolled courses: " << newStudent.courses[i] << endl;
}
cout << endl;
break;
//Stops searching
}
else
//Ignores rest of line - used to skip to the next line
{
getline(inFile, ID, '\n');
}
if (inFile.eof())
//If ID was not found
{
inFile.close();
cout << "Enter First Name: ";
//Begin entry of new student
cin >> newStudent.fName;
cout << endl;
cout << "Enter Last Name: ";
cin >> newStudent.lName;
cout << endl;
outFile.open("registration.txt", ios::app);
if (outFile.is_open())
{
outFile << newStudent.ID << "," << newStudent.fName << "," << newStudent.lName << "\n";
}
}
}
}
return newStudent;
}
Thanks in advance for any help.
The problem is that std::getline takes exactly one character as a delimiter. It defaults to a newline but if you use another character then newline is NOT a delimiter any more and so you end up with newlines in your text.
The answer is to read the entire line into a string using std::getline with the default (newline) delimiter and then use a string stream to hold that line of text so you can call std::getline with a comma as a delimiter.
Something like this:
#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>
int main()
{
std::ifstream inFile("registration.txt");
if (inFile.is_open())
{
std::string line;
while( std::getline(inFile,line) )
{
std::stringstream ss(line);
std::string ID, fname, lname;
std::getline(ss,ID,','); std::cout<<"\""<<ID<<"\"";
std::getline(ss,fname,','); std::cout<<", \""<<fname<<"\"";
std::getline(ss,lname,','); std::cout<<", \""<<lname<<"\"";
std::vector<std::string> enrolled;
std::string course;
while( std::getline(ss,course,',') )
{
enrolled.push_back(course); std::cout<<", \""<<course<<"\"";
}
std::cout<<"\n";
}
}
return 0;
}
In this example I am writing the text to the screen surrounded by quotes so you can see what is read.
split(string, seperator)
split("918273645,Steve,Albright,ITCS2530,MATH210,ENG140", ",")
split("123456789,Kim,Murphy,ITCS2530,MATH101", ",")
split("213456789,Dean,Bowers,ITCS2530,ENG140", ",")
split("219834765,Jerry,Clark,MGMT201,MATH210", ",")
I know very little C++, but I remember this command.
My assignment states the following :
Three employees in a company are up for a special pay increase. You are given a file, Ch3_Ex7Data.txt, with the following data:
Miller Andrew 65789.87 5
Green Sheila 75892.56 6
Sethi Amit 74900.50 6.1
Each input line consists of an employee's last name, first name, current salary, and percent pay increase.
For example, in the first input line, the last name of the employee is Miller, the first name is Andrew, the current salary is 65789.87, and the pay increase is 5 %.
Write a program that reads data from the specified file and stores the output in the file Ch3_Ex7Output.dat. For each employee, the data must be output in the following form: firstName lastName updatedSalary Format the output of decimal numbers to two decimal places.
My code is the following.
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
int main()
{
//Declaring the variables
string firstName;
string lastName;
double payIncrease;
double pay;
ifstream inFile;
ofstream outFile;
inFile.open("C:\\Users\\Megan\\Ch3_Ex7Data.txt"); //opens the input file
outFile.open("C:\\Users\\Megan\\Ch3_Ex7Output.dat"); //opens a output file
outFile << fixed << showpoint;
outFile << setprecision(2); // Output file only having two decimal places
cout << "Processing Data....." endl; //program message
while (!inFile.eof() //loop
inFile >> lastName >> firstName >> pay >> payIncrease;
pay = pay*(pay*payIncrease);
outFile << firstName << " " << lastName << " " << pay << "/n";
inFile.close();
outFile.close();
return 0;
}
For some reason I cannot seem to get the code to open my existing .txt file, read it and then translate it to another file. Does anybody see anything wrong with this that could help me out?
You have many problems with you code.
The two most evident prevent the program from compiling:
cout << "Processing Data....." endl; //program message
should be:
cout << "Processing Data....." << endl; //program message
and while (!inFile.eof() //loop should be at least while (!inFile.eof() )//loop
That's not all:
while (!inFile.eof()) is an anti-idiom: you test for end of file, then read and do the processing even if an error or end of file has occured. You must test after reading.
And as you were said in comment, without { } only the first line after the while is repeated, which is not what you want.
The correct formula to add a percent increase is pay = pay*(1 + payIncrease/100.); at least pay = pay+(pay*payIncrease/100.);
Adding a '/n' as an end of line is plain wrong. The character is '\n' (note the backslash), and anyway you should always write endl in C++.
Once all that is fixed, the loop becomes:
for (;;) { //loop
inFile >> lastName >> firstName >> pay >> payIncrease;
if (! inFile) break; // exit on eof or error
pay = pay*(1 + payIncrease/100.);
outFile << firstName << " " << lastName << " " << pay << endl;
}
and the output is:
Andrew Miller 69079.36
Sheila Green 80446.11
Amit Sethi 79469.43
But is you want to learn good pratices, you should also:
test the opening of both files
test after end of loop if the termination was caused by an error and issue a warning
last by not least learn to use a debugger...
This was my solution
#include <iostream>
#include <fstream>
#include <iomanip>
using namespace std;
int main() {
// Write your main here
//Declarations
string FirstName;
string LastName;
double Pay;
double Increase;
double UpdatedSalery;
//File object and open txt and dat files per instructions and use user input for the txt input file
ifstream FileIn;
string FileName;
cout << "enter a file name: ";
cin >> FileName;
FileIn.open(FileName);
ofstream FileOut("Ch3_Ex5Output.dat");
FileOut << setprecision(8);
while(FileIn >> LastName >> FirstName >> Pay >> Increase){
UpdatedSalery = ((Pay*(Increase/100))+Pay);
FileOut << " " << FirstName << " " << LastName << " " << UpdatedSalery << endl;
}
FileIn.close();
FileOut.close();
return 0;
}
Okay, so I have an input file input.txtthat contains a CSV sequence: 1,1,1,2,2,3,3,4,4
and I am trying to separate it at the commas using a stringstream; however I'm getting a little problem here. For some reason the first number from the sequence is not even getting read by the stream. To show this, I created a some debugging code to see what is happening and I found out that the first number is being stored inside csvLine and every other number is being read and coverted just fine. I don't understand why just the first number is being omitted. Below is an example pic showing exactly what I mean. num should have the same exact values and Line, but it's not. It has all the values except the first one, which is being stored inside csvLine. Why is this happening?!
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
int main(int argc, const char * argv[]) {
ifstream file;
string line;
string csvLine; //comma seperated value line
int num = 0;
file.open(argv[1]);
if(file.is_open()) {
while(getline(file, line)) { //get the whole line and use string stream to break at commas
cout << "\nLine: " << line << endl;
//using stringstream to seperate at commas
stringstream ss(line);
while(getline(ss, csvLine, ',')) {
cout << "csvLine: " << csvLine << " " << endl;
//using stringstream to convert to int
ss >> num;
cout << "num: " << num << " " << endl;
}
}
}
return 0;
}
The problem arises since you're using getline and then extracting integer from your stringstream
You should only use getline
while(getline(ss, csvLine, ','))
{
cout << "csvLine: " << csvLine << " " << endl;
num = std::stoi( csvLine ) ;
}
When you read getline(ss, csvLine, ',') the first time it reads the number followed by the the ','. For the next numbers it just reads the comma as the number was already extracted using ss >> num. That is, the simplest fix is to only read everything up to and including the comma after the loop was executed. Since the value of string extracting the comma isn't used it makes sense to use ignore() instead of std::getline():
for (; ss >> num; ss.ignore(std::numeric_limits<std::streamsize>::max(), ',')) {
// do something with the number
}
Restructuring the loop this way has the added benefit that it is checked whether reading the number was successful.
I can't figure out why this won't read from my file...
#include <iostream>
#include <iomanip>
#include <string>
#include <fstream>
using namespace std;
int main()
{
int acctNum;
int checks;
double interest;
double acctBal;
double monthlyFee;
const int COL_SZ = 3;
ifstream fileIn;
fileIn.open("BankAccounts.txt");
if(fileIn.fail())
{
cout << "File couldn't open." << endl;
}
else
{
cout << left;
cout << "Bank Account records:" << endl;
cout << setw(COL_SZ) << "Account#" << setw(COL_SZ) <<
"Balance" << setw(COL_SZ) << "Interest" << setw(COL_SZ) << "Monthly Fee" << setw(COL_SZ) <<
"Allowed Checks" << setw(COL_SZ) << endl;
while(fileIn >> acctNum >> acctBal >> interest >> monthlyFee >> checks)
{
cout << setw(COL_SZ) << acctNum << setw(COL_SZ) << acctBal << setw(COL_SZ) << interest << setw(COL_SZ) <<
monthlyFee << setw(COL_SZ) << checks << endl;
}
}
fileIn.close();
system("pause");
return 0;
}
I took out the ios::out and put in ios::in same thing happened no data and the same thing with taking ios out all together. I did make the file from a previous program...would i have to put the reading of the files code into that program?
Edit
Looking at your input you can't read such complex input with just
while(fileIn >> acctNum >> acctBal >> monthlyFee >> checks)
This code is setup to read data formatted in the following form:
11 12.12 11.11 13.13 14.12
11 12.12 11.11 13.13 14.12
11 12.12 11.11 13.13 14.12
Instead you'll have to read the various strings and such before scraping out the data you need. For example to skip over the word "Account" below, you can read it into a dummy string
Account Number#1234
std::string dummy;
fileIn >> dummy; // read up to the whitespace,
// in this case reads in the word "Account"
Then To get the number you'll have to read the next string and extract the #1234
std::string temp;
fileIn >> temp; // read up to the whitespace,
// in this case reads in the word "Number#1234"
But you could also use getline to read up to and including the #
std::getline(fileIn, dummy, '#');
Then read in the number after the #
int acctNum = 0;
fileIn >> acctNum;
So if you're input is truly formatted as you describe, you'll have to spend a lot more time figuring out how to parse your data then you may have expected. I don't know enough about how your input is expected to give you a complete answer, but the above should hopefully get you started.
(Optionally, you could learn about regular expressions, but at this point you may just want to learn the basics.)
Original
I just tried your code out and with enough well-formatted values in the input, it works in g++. However, one thing that I am wary of looking at your code is this line:
while(fileIn >> acctNum >> acctBal >> monthlyFee >> checks)
If any of the above fails to read due to the file ending prematurely, your cout isn't going to get executed, causing no output to the screen. Does your input have all the above values? Are they well formatted? To debug I might try breaking up the reads:
while (fileIn)
{
fileIn >> acctNum;
std::cout << "Acct num is:" << acctNum << std::endl;
...
}
or just step through with a debugger.
For example for this input:
11 12.12 11.11 13.13 14.12
your code prints out
Bank Account records:
Account#BalanceInterestMonthly FeeAllowed Checks
11 12.126.93517e-31011.1113 `
But screwing with the input and adding a random non numeric character somewhere, ie:
11 * 12.12 11.11 13.13 14.12
causes me to get just
Bank Account records:
Account#BalanceInterestMonthly FeeAllowed Checks
So I would definitely look piece-by-piece at what's getting read and where a read from fileIn is failing, this would definitely cause your problems.
You know of course to remove the ios::out as specified here
You have
fileIn.open("BankAccounts.txt", ios::out);
^^^^^^^^
You're opening the file for output. Try ios::in.