I'm trying to read a file and write the data I read into a structure. With the getline function, i read the whole line, and then divide it in columns. Each term goes into an argument of the structure, and each line is a new instance of the structure. The problem is that my first column is empty.
The folowing code works partially, I read the whole file, all the other columns work perfectly but the first one is filled with nothing.
this is my structure and the data I put into it :
struct employe {
int num_employe;
string nom;
string prenom;
string date_naissance;
string ville_resi;
int code_postal;
};
employe saisir_1_employe(vector<string> row) {
employe e;
e.num_employe = stoi(row[0]);
e.nom = row[1];
e.prenom = row[2];
e.date_naissance = row[3];
e.ville_resi = row[4];
e.code_postal = stoi(row[5]);
return (e);
}
I extract the data from the file like this :
if (myfile.is_open()) {
while (myfile >> temp) {
row.clear();
// read an entire row and
// store it in a string variable 'line'
getline(myfile, line, '\n');
istringstream s(line);
// read every column data of a row and
// store it in a string variable, 'word'
while (getline(s, word, '\t')) {
// add all the column data
// of a row to a vector
row.push_back(word);
}
e = saisir_1_employe(row);
afficher_1_employe(e);
}
}
my file I extract the data from looks like this : https://pastebin.com/Nfhu2tEp
When I display the second column (cout << row[1]) i get the names perfectly. But when I do cout << row[0] i get an empty column when it is supposed to be a string that I then convert to an int with e.num_employe = stoi(row[0]). It's there and has the right number of lines but just empty.
I think you should loop like this
while(std::getline(myfile, line, '\n'))
instead of
while (myfile >> temp)
which is cutting away the first word in every line ...
Use getline() by itself to get each line
There is no need to use this line:
while(myfile >> temp)
This is grabbing the first word and is never called again.
Instead, loop on each line, by calling getline() on the filestream directly:
while (getline(myfile, line, '\n'))
I like your use of stringstream to parse the words. I probably would have used a stringstream in the saisir function as well to do the parsing calls (e.g. instead of stoi()).
#include <string>
#include <sstream>
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
struct employe {
int num_employe;
string nom;
string prenom;
string date_naissance;
string ville_resi;
int code_postal;
};
employe saisir_1_employe(vector<string> row )
{
employe e;
e.num_employe = stoi(row[0]);
e.nom = row[1];
e.prenom = row[2];
e.date_naissance = row[3];
e.ville_resi = row[4];
e.code_postal = stoi(row[5]);
return (e);
}
int main()
{
fstream myfile{"myfile.txt"};
std::string line;
std::string word;
std::vector<employe> employees;
if (myfile.is_open()) {
// while (myfile >> temp) {
//
// row.clear();
// read an entire row and
// store it in a string variable 'line'
while (getline(myfile, line, '\n')) {
std::vector<std::string> row;
std::istringstream sline(line);
// read every column data of a row and
// store it in a string variable, 'word'
while (getline(sline, word, '\t')) {
// add all the column data
// of a row to a vector
row.push_back(word);
}
employe e;
e = saisir_1_employe(row);
employees.push_back(e);
// afficher_1_employe(e);
}
int index = 1;
// dump number and nom
for(const auto& emp : employees) {
std::cout << index++ << ". " << emp.num_employe
<< " " << emp.nom << std::endl;
}
}
}
Related
Just quick one, how should I go about printing a value from a struct? the 'winningnums' contains a string from another function (edited down for minimal example)
I've tried the below but the program doesnt output anything at all, is my syntax incorrect?
struct past_results {
std::string date;
std::string winningnums;
};
int main(){
past_results results;
std::cout << results.winningnums;
return 0;
}
EDIT:
just to give some more insight, here's the function that populates my struct members. Is it something here im doing wrong?
//function to read csv
void csv_reader(){
std::string line;
past_results results;
past_results res[104];
int linenum = 0;
//open csv file for reading
std::ifstream file("Hi S.O!/path/to/csv", std::ios::in);
if(file.is_open())
{
while (getline(file, line))
{
std::istringstream linestream(line);
std::string item, item1;
//gets up to first comma
getline(linestream, item, ',');
results.date = item;
//convert to a string stream and put into winningnums
getline(linestream, item1);
results.winningnums = item1;
//add data to struct
res[linenum] = results;
linenum++;
}
}
//display data from struct
for(int i = 0; i < linenum; i++) {
std::cout << "Date: " << res[i].date << " \\\\ Winning numbers: " << res[i].winningnums << std::endl;
}
}
is my syntax incorrect?
No, it's just fine and if you add the inclusion of the necessary header files
#include <iostream>
#include <string>
then your whole program is ok and will print the value of the default constructed std::string winningnums in the results instance of past_results. A default constructed std::string is empty, so your program will not produce any output.
Your edited question shows another problem. You never call csv_reader() and even if you did, the result would not be visible in main() since all the variables in csv_reader() are local. Given a file with the content:
today,123
tomorrow,456
and if you call csv_reader() from main(), it would produce the output:
Date: today \\ Winning numbers: 123
Date: tomorrow \\ Winning numbers: 456
but as I mentioned, this would not be available in main().
Here's an example of how you could read from the file and make the result available in main(). I've used a std::vector to store all the past_results in. It's very practical since it grows dynamically, so you don't have to declare a fixed size array.
#include <fstream>
#include <iostream>
#include <sstream> // istringstream
#include <string> // string
#include <utility> // move
#include <vector> // vector
struct past_results {
std::string date;
std::string winningnums;
};
// added operator to read one `past_results` from any istream
std::istream& operator>>(std::istream& is, past_results& pr) {
std::string line;
if(std::getline(is, line)) {
std::istringstream linestream(line);
if(!(std::getline(linestream, pr.date, ',') &&
std::getline(linestream, pr.winningnums)))
{ // if reading both fields failed, set the failbit on the stream
is.setstate(std::ios::failbit);
}
}
return is;
}
std::vector<past_results> csv_reader() { // not `void` but returns the result
std::vector<past_results> result; // to store all past_results read in
// open csv file for reading
std::ifstream file("csv"); // std::ios::in is default for an ifstream
if(file) {
// loop and read records from the file until that fails:
past_results tmp;
while(file >> tmp) { // this uses the `operator>>` we added above
// and save them in the `result` vector:
result.push_back(std::move(tmp));
}
}
return result; // return the vector with all the records in
}
int main() {
// get the result from the function:
std::vector<past_results> results = csv_reader();
// display data from all the structs
for(past_results& pr : results) {
std::cout << "Date: " << pr.date
<< " \\\\ Winning numbers: " << pr.winningnums << '\n';
}
}
Your example doesn't initialize the struct members. There is no data to print, so why would you expect it to output anything?
Output:
cola
coke
3
I want these values to be stored in an array. Please guide me how to!
TIA
This is the code:
int cola(string str)
{
// word variable to store word
string word;
// making a string stream
stringstream iss(str);
// Read and print each word.
while (iss >> word)
{cout << word << endl;}}
// Driver code
int main()
{
string s = "cola coke 3";
cola(s);
return 0;
}
Is this what you are looking for:
using std::string;
std::vector<string> cola(const string& str)
{
// word variable to store word
string word;
// making a string stream
stringstream iss(str);
// vector containing words
std::vector<string> temp;
// Read and print each word.
while (iss >> word)
temp.push_back(word);
return std::move(temp);
}
// Driver code
int main()
{
string s = "cola coke 3";
std::vector<string> array = cola(s);
return 0;
}
In the program im currently writing, im up to a stage that requires the use of data that has been read through a file. Some of this data contains number elements, so the proper conversions have been done in order to store them in a vector of type string. Up to this point works.
I have a function called robotComplexity, which calculates a value based on other values found in the file, which have already been added to a vector List(all code shall be posted below). The text file contains the following data.
A:Head:1:2:15.
B:Torso:0:6:5.
C:Leg:0:4:6.
D:Arm:0:4:8.
E:Tail:0:6:2.
As seen in the code below, this file has been split by a dilimiter at the colon and fullstop to first seperate the variables, then the records. The variables have been stored in their respective holders as shown in the code. The function called robotComplexity contains a for loop
for(std::size_t i=0; i< partsVector.size(); ++i) {
if(partsVector[i] == userChoice) {
cout << userChoice << stoi(stringMaximum) << endl;
}
The issues with my Code stem from this for loop. The program is able to loop through the file and recongise the first variable, partCode(converted to newChar) of respective values A,B,C,D,E. So for example when a user enters A it returns A, enters B returns B etc. Now my issues come from trying to print out other variables stored in the vector. In the cout << userChoice...etc line, it successfully returns the Letter(example A) but does not return the correct Value for stringMaximum converted to an int. The returned value is 0 where it should be whatever it equals for a partCode A(in this case)
Im asking if anyone could create/fix my for loop such that when cout << "Variable" is called, it can successfuly print to the console the value of that variable according to the partCode
For Example, if the user enters A as the partcode the output should be
code
cout << userChoice << partName << stringMaximum << stringMinimum << stringComplexity << endl;
output
A
Head
1
2
15
file containing functions
struct Part {
char partCode;
std::string partName;
int maximum;
int minimum;
int complexity;
} myPart;
std::vector<string> partsVector;
std::ifstream partsList("Parts.txt");
std::string outputFile = "output.txt";
std::string input;
std::string newChar;
std::stringstream convertChar;
std::string stringMaximum = std::to_string(myPart.maximum);
std::string stringMinimum = std::to_string(myPart.minimum);
std::string stringComplexity = std::to_string(myPart.complexity);
void readFile() //function to read Builders, Customers and Parts text file
{
std::string line;
while (std::getline(partsList, line)) {
line.pop_back();//removing '.' at end of line
std::string token;
std::istringstream ss(line);
convertChar << myPart.partCode;
convertChar >> newChar;
// then read each element by delimiter
int counter = 0;//number of elements you read
while (std::getline(ss, token, ':')) {//spilt into different records
switch (counter) {//put into appropriate value-field according to element-count
case 0:
newChar = token; //convert partCode from a char to a string
break;
case 1:
myPart.partName = token;
break;
case 2:
myPart.maximum =stoi(token);
break;
case 3:
myPart.minimum = stoi(token);
break;
case 4:
myPart.complexity = stoi(token);
break;
default:
break;
}
counter++;//increasing counter
}
partsVector.push_back(newChar);
partsVector.push_back(myPart.partName);
partsVector.push_back(stringMaximum);
partsVector.push_back(stringMinimum);
partsVector.push_back(stringComplexity);
}
}
double robotComplexity() {
double complexity;
string userChoice;
cout << "Enter a part code A ,B ,C ,D or E" << endl;
cin >> userChoice;
for(std::size_t i=0; i< partsVector.size(); ++i) {
if(partsVector[i] == userChoice) {
cout << userChoice << stoi(stringMaximum) << endl;
}
}
}
Thankyou for any help offered. If any furuther explaination is required please feel free to ask. PS I know global variables aren't the best to use, but once my functions operate correctly I will clean the code up with local variables.
There are several issues here, but your main problem is that
std::string stringMaximum = std::to_string(myPart.maximum);
std::string stringMinimum = std::to_string(myPart.minimum);
std::string stringComplexity = std::to_string(myPart.complexity);
are global variables, and not functions. They will be evaluated only once at the beginning of your program. So your readFile is already broken in the code that you gave us. The first thing I would do is remove the global state (i.e. remove all global variables) and fix the code that doesn't compile anymore.
You do
partsVector.push_back(stringMaximum);
partsVector.push_back(stringMinimum);
in readFile without ever setting those two variables so you always push the same value in your vector.
Next question is, why do you use a vector of string and not a vector of Part? You already parse the file to Part objects, so just use them. Furthermore, you want to access those parts via a user input that queries for Part.partCode, so we can use a lookup table with partCode as a key (std::unordered_map<char, Part> in this case).
All in all this would look like the following (the inner while loop in readFile was a nightmare too, so I removed that aswell):
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <iostream>
#include <unordered_map>
struct Part
{
char partCode = 0;
std::string partName;
int maximum = 0;
int minimum = 0;
int complexity = 0;
};
std::stringstream partsList(
R"(A:Head:1:2:15.
B:Torso:0:6:5.
C:Leg:0:4:6.
D:Arm:0:4:8.
E:Tail:0:6:2.)");
std::string outputFile = "output.txt";
std::string input;
std::unordered_map<char, Part> readFile() //function to read Builders, Customers and Parts text file
{
std::unordered_map<char, Part> parts;
std::string line;
while (std::getline(partsList, line))
{
line.pop_back(); //removing '.' at end of line
std::string token;
std::istringstream ss(line);
Part part;
std::getline(ss, token, ':');
part.partCode = token[0];
std::getline(ss, part.partName, ':');
std::getline(ss, token, ':');
part.maximum = std::stoi(token);
std::getline(ss, token, ':');
part.minimum = std::stoi(token);
std::getline(ss, token, ':');
part.complexity = std::stoi(token);
parts.emplace(part.partCode, std::move(part));
}
return parts;
}
double robotComplexity(std::unordered_map<char, Part> const& parts)
{
double complexity = 10;
char partCode;
std::cout << "Enter a part code A ,B ,C ,D or E" << std::endl;
std::cin >> partCode;
auto const& part = parts.at(partCode);
std::cout << part.maximum;
if (complexity > 100)
{
complexity = 100;
}
std::cout << "\nThe Robot Complexity is: " << complexity << std::endl;
return complexity;
}
void writeFile() //writes to a file output.txt the end calculations.
{
}
int main()
{
auto parts = readFile();
writeFile();
robotComplexity(parts);
return 0;
}
How do I read in lines from a file and assign specific segments of that line to the information in structs? And how can I stop at a blank line, then continue again until end of file is reached?
Background: I am building a program that will take an input file, read in information, and use double hashing for that information to be put in the correct index of the hashtable.
Suppose I have the struct:
struct Data
{
string city;
string state;
string zipCode;
};
But the lines in the file are in the following format:
20
85086,Phoenix,Arizona
56065,Minneapolis,Minnesota
85281
56065
I cannot seem to figure this out. I am having a really hard time reading in the file. The first line is basically the size of the hash table to be constructed. The next blank line should be ignored. Then the next two lines are information that should go into the struct and be hashed into the hash table. Then another blank line should be ignored. And finally, the last two lines are input that need to be matched to see if they exist in the hash table or not. So in this case, 85281 is not found. While 56065 is found.
This is what I have and it doesn't seem to be doing what I want it to do:
int main(int argc, char *argv[])
{
string str;
//first line of file is size of hashtable
getline(cin, str);
stringstream ss(str);
int hashSize;
ss >> hashSize;
//construct hash table
Location *hashTable = new Location[hashSize];
//skip next line
getline(cin, str);
string blank = " ";
while(getline(cin, str))
{
{
//next lines are data
Location locate;
string line;
getline(cin, line);
istringstream is(line);
getline(is, locate.zipCode, ',');
getline(is, locate.city, ',');
getline(is, locate.state, ',');
insertElementIntoHash(hashTable, locate, hashSize);
}
}
dispHashTable(hashTable, hashSize);
//read third set of lines that check if the zipCodes are in the hashtable or not
while(getline(cin, str))
{
//stop reading at a blank line or in this case, end of file
stringstream is(str);
string searchZipCode;
is >> searchZipCode;
searchElementInHash(hashTable, hashSize, searchZipCode);
}
//delete hash table after use
delete []hashTable;
return 0;
}
You might read the input this way:
#include <iostream>
#include <sstream>
#include <vector>
struct Location
{
std::string city;
std::string state;
std::string zipCode;
};
int main(int argc, char *argv[]) {
std::istringstream input(
"2\n"
"\n"
"85086,Phoenix,Arizona\n"
"56065,Minneapolis,Minnesota\n"
"\n"
"85281\n"
"56065\n"
);
// Make the size unsigned, to avoid signed/unsigned compare warnings.
unsigned hashSize;
std::string line;
getline(input, line);
std::istringstream hash_line(line);
// Ignore white space.
if( ! (hash_line >> hashSize >> std::ws && hash_line.eof())) {
std::cerr << "Error: Invalid file format [1].\n" << line << '\n';
return -1;
}
else {
getline(input, line);
std::istringstream first_blank_line(line);
// Ignore white space.
first_blank_line >> std::ws;
if( ! first_blank_line.eof()) {
// Missing blank line.
std::cerr << "Error: Invalid file format [2].\n" << line << '\n';
return -2;
}
else {
// Have a local variable (No need to allocate it)
// (Is it a hash table !???)
std::vector<Location> hashTable;
hashTable.reserve(hashSize);
while(hashTable.size() < hashSize && getline(input, line)) {
std::istringstream data_line(line);
Location locate;
getline(data_line, locate.zipCode, ',');
getline(data_line, locate.city, ',');
getline(data_line, locate.state); // Note: No comma here.
if(data_line && data_line.eof()) {
// Note: The fields may have leading and/or trailing white space.
std::cout
<< "Insert the location into the hash table.\n"
<< locate.zipCode << '\n'
<< locate.city << '\n'
<< locate.state << '\n';
hashTable.push_back(locate);
}
else {
std::cerr << "Error: Invalid file format [3].\n" << line << '\n';
return -3;
}
}
if(hashTable.size() != hashSize) {
std::cerr << "Error: Invalid file format [4].\n";
return -4;
}
else {
getline(input, line);
std::istringstream second_blank_line(line);
// Ignore white space.
second_blank_line >> std::ws;
if( ! second_blank_line.eof()) {
// Missing blank line.
std::cerr << "Error: Invalid file format [5].\n";
return -5;
}
else {
std::string searchZipCode;
while(input >> searchZipCode) {
// Search element in the hash table
}
}
}
}
}
return 0;
}
Following modification should work:
//skip next line
getline(cin, str);
string blank = " ";
string line;
while(getline(cin, line) && (line != ""))
{
{
//next lines are data
Location locate;
istringstream is(line);
getline(is, locate.zipCode, ',');
getline(is, locate.city, ',');
getline(is, locate.state, ',');
insertElementIntoHash(hashTable, locate, hashSize);
}
}
i have written a program to just detect the commas in a .csv file and copy the data into a structure ... but it also detects the comma in the text of each cell like if i have burgerking,AK in one cell then it will also detect the comma between burgerking and AK making it hard to copy the data in one cell to a string array in structure so can any one help me to copy the data present in each cell in .csv file into string file in a strcture in c++
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
struct burgerking //structure containing different strings for each column in .csv file
{
string longitude[7000];
string latitude[7000];
string location[7000];
string state[7000];
string address[7000];
};
void main () {
burgerking *burger;
burger= new burgerking();
string line;
ifstream myfile;
myfile.open("burgerking.csv"); //opening the csv file
if(myfile.good())
cout<<"File is Good to be opened"<<endl;
int l=0; //longitude
int n=1; //latutude
int e=2; //location
int ss=3; //state
int ad=4; //address
int j=0;
int b=0;
int kk=0;
int ll=0;
int add=0;
string line1;
string line2;
string line3;
for(int i=0;i<1500;i++)
{
getline(myfile,line,',');
if(i==0)
{
burger->longitude[j]=line;
j++;
l=l+7;
}
if(i==l)
{
burger->longitude[j]=line.substr(16,line.length());
j++;
l=l+7;
}
if(i==n)
{
burger->latitude[b]=line;
n=n+7;
b++;
}
if(e==i)
{
burger->location[kk]=line;
kk=kk+1;
e=e+7;
}
if(ss==i)
{
burger->state[ll]=line;
ss=ss+7;
ll++;
}
}
myfile.close();
myfile.open("burgerking.csv");
for(int c=0;c<2000;c++)
{
getline(myfile,line,',');
if(ad==c)
{
getline(myfile,line1,',');
getline(myfile,line2,',');
getline(myfile,line3,',');
line3=line3.substr(0,16);
burger->address[add]=line+','+line1+','+line2+','+line3;
add++;
ad=ad+4;
}
}
for(int k=0;k<300;k++)// loop just to check the program output
{
cout<<'\t'<<'\t'<<k+1<<endl;
cout<<burger->longitude[k]<<" ";
cout<<burger->latitude[k]<<" ";
cout<<burger->location[k]<<" ";
cout<<burger->state[k]<<" ";
cout<<burger->address[k]<<endl<<endl<<endl; //just to check the output
}
myfile.close();
system("PAUSE");
}
I would say that you are going about it all wrong.
To start with your structures should not contain arrays of strings, instead you should have one structure instance per store, and then store them in a std::vector:
So
struct burgerking
{
std::string longitude;
std::string latitude;
std::string location;
std::string state;
std::string address;
};
and
std::vector<burgerking> stores;
Then when reading the file, you use std::getline to get a complete line, and use std::istringstream with std::getline to get the separate values:
std::string line;
while (std::getline(myfile, line))
{
std::istringstream iss(line);
burgerking burger; // No pointers needed
std::getline(iss, burger.longitude, ',');
std::getline(iss, burger.latitude, ',');
std::getline(iss, burger.location, ',');
std::getline(iss, burger.state, ',');
std::getline(iss, burger.address); // Last field, no separator needed
stores.push_back(burger); // Add to collection
}
And finally when you're printing them out, use e.g.
for (const burgerking& b : stores)
{
std::cout << "Longitude: " << b.longitude << '\n';
// Etc.
}