I know how to read a file with ifstream etc. I am just stuck on this task where I have a header file full of constants and a text file with 3 variables (budget, hotelType, [event1, event2, …, eventn]).
#ifndef CONSTANTS_H_
#define CONSTANTS_H_
const string nameMap[] = { "Opening", "Soccer 1", "Soccer 2", "Soccer 3",
"Track and Field 1", "Track and Field 2", "Track and Field 3",
"Track and Field 4", "Swimming 1", "Swimming 2", "Gymnastics 1",
"Gymnastics 2", "Basketball 1", "Basketball 2", "Closing" };
const int eventPriceMap[] = { 2000, 80, 160, 500, 80, 100, 120, 140, 100, 100, 60, 100,
150, 300, 800 };
const int eventDateMap[] = { 0, 3, 6, 9, 1, 2, 3, 4, 5, 6, 7, 8, 5, 7, 9 };
const int eventQuota[] = {60, 47, 30, 22, 50, 52, 42, 25, 37, 20, 43, 34, 35, 30, 40};
const int hotelPriceMap[] = {160, 210, 320};
const int hotelQuota[] ={20, 25, 30};// per day
const int MAXEVENTS = 10;
const int MAXREQUESTS = 150;
const int NUMBEROFEVENTS = 15;
const int NUMBEROFDAYS = 10;
#endif /* CONSTANTS_H_ */
9020,4[2,0,5,14,10,4,3,13,1]
7805,5[13,3,12,12,0,9,7,10,6,1]
7075,5[3,2,4,9,7,0,1,5,6,14]
7679,4[0,4,14,1,3,12,5,10]
6356,3[7,3]
6874,5[14,0,4,10,9,3]
4715,4[9]
4784,5[11]
4321,3[5,3,8,9]
6469,5[7,6,6,14,12,5,2]
4838,4[1,2]
4103,3[14]
5904,5[5,4,6]
5775,3[10,14,14,8,7,3,4]
7070,4[1,4,6,11,13,3,2,5,14]
4605,3[6,10,1,8,7,3,3]
7484,4[11,5,14,2,6,7,8,1,0]
Within another file how would I go about reading this text document and saving it into Budget, hotelType, and [events]. I absolutely have no idea im still learning c++, thankyou to anyone who helps!
Edit: I dont think the constants header file is necessary for this. My apologies
There might be different approaches to reading formatted data in C++. The most straight-forward is to use capabilities of the input stream, that you've said you are familiar with. It can read integers for you, and you just need to manually skip all the separators.
Let's assume you store your data as an array of these structs:
struct Entity
{
int budget;
int hotel_type;
std::vector<int> events;
};
And you need to populate std::vector<Entity> entities
. If your data are passed to the standard input, the parsing code would be:
while (cin) {
Entity entity;
char separator;
cin >> entity.budget >> separator >> entity.hotel_type >> separator;
while (cin && separator != ']') {
int event;
cin >> event >> separator;
entity.events.push_back(event);
}
if (cin)
entities.push_back(std::move(entity));
}
This simple implementation does not check that the format is strictly as expected. Ie it simply reads a separating character into the separator
variable. You can add a check that it is indeed a comma, or a square bracket.
Note this last if (cin)
at the end. If we try reading data from a stream which does not have them (ie it has already deplenished), the internal eofbit
flag is set to the stream. We check it by simply providing the string variable as a condition, because it has operator bool()
defined, which checks the eofbit
flag for us (and some other flags too). We need to check it after the reading to make sure the reading was successful.
You can see this code in action here: https://rextester.com/MDZDG18083
In this demo I'm using a custom std::stringstream
wrapping a provided data, but the code will work on any provided input stream.
If I understand your question correctly, here is a solution to solve your problem. According to your file, you need three variables:
So based on this the solution could be:
budget[] = {9020,7805,7075,7679,6356,6874,4715 ...}
hotelType[] = {4,5,5,4,3,5 ...}
events[][] = {{2,0,5,14,10,4,},{13,3,12,12,0,9,7,10,6,1},{3,2,4,9,7,0,1,14} ...}
Let me know if I'm on the right track, so that we can proceed to the implementation ...
EDIT
First Solution, using array:
#include <iostream>
#include <string>
#include <fstream>
int main()
{
std::ifstream infile("file.txt");
std::string line;
int budget[100], hotelType[100], events[100][100], index = 0;
while (std::getline(infile, line)){
std::string num;
int i = 0;
for( ; i < line.length(); i++){
if(line[i] != ',' && line[i] != '[' && line[i] != ']')
num += line[i];
else{
budget[index] = std::stoi(num);
num = "";
break;
}
}
i++;
hotelType[index] = std::stoi(line.substr(i, 1));
i++; i++;
for(int j = 0; i < line.length(); i++){
if(line[i] != ',' && line[i] != '[' && line[i] != ']')
num += line[i];
else{
events[index][j] = std::stoi(num);
num = "";
j++;
}
}
index++;
}
for(int i = 0; i < index; i++){
std::cout<< i + 1 << "th: ";
std::cout<< "\tBudget : " << budget[i] << std::endl;
std::cout<< "\tHotel Type: " << hotelType[i] << std::endl;
std::cout<< "\tEvents : " << std::endl;
for(int j = 0; j < 5; j++)
std::cout<< "\t\t" << events[i][j] << std::endl;
}
return 0;
}
it's a string, right? why you don't try to split by the comma transforming into arrays? you can read with buffer line per line and then split by comma (removing the brackets) and saving the values.
First split each line by ',' that return array whit 2 elements
first element is budget and second element is hotelType[event1, event2, …, eventn]
then you should get string between "[" , "]" and again split by , and that return array with multi length
I've tried to describe this solution by comments in the code. It basically just defines stream operators to be able to read/write the data from any stream.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <ios>
#include <sstream>
#include <stdexcept>
// create an alias for a number of events using a standard container
// for int's, std::vector<int>
using EventList = std::vector<int>;
// add an input stream operator for our EventList to be able to read
// and split strings looking like [int,int,...,int]
std::istream& operator>>(std::istream& is, EventList& el) {
std::string tmp; // a temporary string
el.clear(); // remove any existing events
if(std::getline(is, tmp)) { // read until end-of-line
// check that we got [ and ]
if(tmp.size()<2 || tmp[0] != '[' || tmp[tmp.size()-1] != ']') {
// wrong format, set the input streams failbit
is.setstate(std::ios::failbit);
} else {
// remove the first and last character [ and ]
tmp = tmp.substr(1, tmp.size()-2);
// put the string in a string stream to be able
// to use std::getline with a delimiter
std::stringstream ss(tmp);
// loop until the stringstream is empty
while( std::getline(ss, tmp, ',') ) {
// tmp should now be a string of digits
// use stoi to convert the string to an int
try {
int an_int = std::stoi(tmp);
// put the int at the back of our EventList
el.emplace_back(an_int);
} catch(const std::invalid_argument& ex) {
// the conversion to an int failed
// set the input streams failbit
is.setstate(std::ios::failbit);
}
}
}
} else {
// getline failed, set the failbit on the stream
is.setstate(std::ios::failbit);
}
return is;
}
// add an output stream operator for EventList to be able to output
// it in the same format as it was read
std::ostream& operator<<(std::ostream& os, const EventList& el) {
os << "[";
if(el.size()) { // check that we have events to stream
// create an iterator that points at the first element
EventList::const_iterator it = el.begin();
// dereference the iterator to get the int it points to
// and stream that int
os << *it;
++it; // step to the next event
// loop until the iterator points beyond the last element
// in the EventList
for(;it!=el.end(); ++it) {
// prepend each event with a comma
os << "," << *it;
}
}
os << "]";
return os;
}
// here's an operator for a vector of EventList's for convenience
// it follows the same pattern as the operator above
std::ostream& operator<<(std::ostream& os, const std::vector<EventList>& vel) {
os << "[";
if(vel.size()) {
std::vector<EventList>::const_iterator it = vel.begin();
os << *it;
++it;
for(;it!=vel.end(); ++it) {
os << " " << *it;
}
}
os << "]";
return os;
}
// one line in your file int,int[int...]
// broken down into a struct
struct OneDataLine {
int budget;
int hotelType;
EventList events; // using the alias created above
// the default constructor with initialization of members
OneDataLine() :
budget(0),
hotelType(0),
events()
{}
// declaring stream operators as friends, allowing them to operate
// on the objects members. this is not really necessary
// since this struct has all members public but if you later decide
// to make them private, this will come in handy
friend std::istream& operator>>(std::istream&, OneDataLine&);
friend std::ostream& operator<<(std::ostream&, const OneDataLine&);
};
// an input stream operator for reading one data line
std::istream& operator>>(std::istream& is, OneDataLine& d) {
char separator;
is >> d.budget >> separator >> d.hotelType;
if(separator != ',') {
// if the separator between budget and hotelType is not
// a comma, set the input stream in a failed state
is.setstate(std::ios::failbit);
} else {
// we should now only have the events part left on
// the line. stream it to the EventList for which we
// have already added an input stream operator
is >> d.events;
}
return is;
}
// an output stream operator for writing one data line
std::ostream& operator<<(std::ostream& os, const OneDataLine& d) {
// int's have built-in stream operators
// and we have also added an output stream operator for
// EventList so streaming becomes easy
os << d.budget << "," << d.hotelType << d.events;
return os;
}
// USAGE: progname datafile1 ... datafileX
int main(int argc, char* argv[]) {
// convert C style main() parameters to a C++ container.
// we use std::vector again, but this time for storing
// strings
std::vector<std::string> args(argv+1, argv+argc);
// yet another vector, but this is for storing data lines
std::vector<OneDataLine> all_data_lines;
// Reading part
// loop over the input parameters to main()
for(const std::string& file : args) {
std::fstream fs(file); // open file for reading
// loop over the opened file for as long as the
// filestream's failbit isn't set
while(fs) {
// a temporary instance of OneDataLine
OneDataLine tmp;
// stream from the open file to our temporary
fs >> tmp;
// if the failbit still isn't set, move the
// content of the temporary variable into
// our vector of data lines
if(fs) all_data_lines.emplace_back(std::move(tmp));
}
// the filestream will be automatically closed
// when it goes out of scope
}
// Writing part
// loop over all the data lines we've collected and
// stream to cout. we could just as well stream to
// a file opened for writing
for(const OneDataLine& line : all_data_lines) {
// stream the complete data line using our own output
// stream operator for OneDataLine
std::cout << line << "\n";
// stream individual members too
std::cout << " budget : " << line.budget << "\n";
std::cout << " hotelType: " << line.hotelType << "\n";
std::cout << " events : " << line.events << "\n";
// and stream each event separately
std::cout << " [\n";
for(const int& ev : line.events) {
std::cout << " " << ev << "\n";
}
std::cout << " ]\n";
}
// Creating containers for each category
std::vector<int> budgets;
std::vector<int> hotelTypes;
std::vector<EventList> event_lists;
// loop through the collected data and put each member in
// the container for its category
for(const OneDataLine& line : all_data_lines) {
budgets.push_back(line.budget);
hotelTypes.push_back(line.hotelType);
event_lists.push_back(line.events);
}
// Output categorized containers
// here we use EventList's (std::vector<int>'s) output stream operator
std::cout << "budgets : " << budgets << "\n";
std::cout << "hotelTypes : " << hotelTypes << "\n";
// and here we use our convenience output stream operator for
// a vector of EventList
std::cout << "event_lists: " << event_lists << "\n";
return 0;
}
Sample output:
% progname datafile
[...skipping to the end...]
7484,4[11,5,14,2,6,7,8,1,0]
budget : 7484
hotelType: 4
events : [11,5,14,2,6,7,8,1,0]
[
11
5
14
2
6
7
8
1
0
]
budgets : [9020,7805,7075,7679,6356,6874,4715,4784,4321,6469,4838,4103,5904,5775,7070,4605,7484]
hotelTypes : [4,5,5,4,3,5,4,5,3,5,4,3,5,3,4,3,4]
event_lists: [[2,0,5,14,10,4,3,13,1] [13,3,12,12,0,9,7,10,6,1] [3,2,4,9,7,0,1,5,6,14] [0,4,14,1,3,12,5,10] [7,3] [14,0,4,10,9,3] [9] [11] [5,3,8,9] [7,6,6,14,12,5,2] [1,2] [14] [5,4,6] [10,14,14,8,7,3,4] [1,4,6,11,13,3,2,5,14] [6,10,1,8,7,3,3] [11,5,14,2,6,7,8,1,0]]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.