Source: text file stores list of account info. e.g:
10041249,Mr,Vincent,Rogan,Rogan Locksmiths Ltd,Nell,5287.000000,,491.691000,
10021250,Mrs,Adele,Cunningham,Cunningham Demolition Ltd,Dr Scott,2941.000000,,273.513000,
10051251,Mr,Rodney,Shaw,Shaw Meat Packaging Ltd,Eddie,7552.000000,,740.096000,
10001252,Mrs,Christine,Nichols,Nichols Scaffolding Ltd,Brad,6723.000000,Eddie:Brad:,672.300000,
10021253,Mr,Alexander,Marshall,Marshall Chemicals Ltd,Dr Scott,1768.000000,,173.264000,
10021254,Ms,Shirley,Hagman,On Point Sportswear Ltd,Dr Scott,52.000000,,5.200000,
....
....
....
How to extract string with comma delimiter from txt file and parse every element separate by comma delimiter into a class constructor?
I have try to use stringstream to extract data from every line. But it does not work. The EmployeeAccount class I got is down below:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class EmployeeAccount {
private:
//member variable
string acountNumber;
string title;
string firstname;
string lastname;
string company;
string salesperson;
double purchaseValue;
string prev_salestaff;
double commission;
public:
//overload constructor
EmployeeAccount(const string& employeeAccountInfo)
{
string str;
stringstream employeeAccountStream(employeeAccountInfo);
while (getline(employeeAccountStream, str, ','))
{
stringstream sso(str);
sso >> acountNumber;
sso >> title;
sso >> firstname;
sso >> lastname;
sso >> company;
sso >> salesperson;
sso >> purchaseValue;
sso >> prev_salestaff;
sso >> commission;
}
}
//Access methods
string getAccountNumber() { return acountNumber; };
string getTitle() { return title; };
string getFirstname() { return firstname; };
string getLastname() { return lastname; };
string getCompany() { return company; };
double getPurchaseValue() { return purchaseValue; };
string getPrev_salesstaff() { return prev_salestaff; };
double getCommission() { return commission; };
string getAccountDetail() { return acountNumber " " title " " firstname " " lastname " " company;};
//Destructor
~EmployeeAccount() {};
};
The testing code is this:
cout << testEmployee.getAccountDetail() << endl;
cout << testEmployee.getAccountNumber() << endl;
cout << testEmployee.getTitle() << endl;
cout << testEmployee.getFirstname() << endl;
cout << testEmployee.getLastname() << endl;
cout << testEmployee.getCompany() << endl;
cout << testEmployee.getPurchaseValue() << endl;
cout << testEmployee.getPrev_salesstaff() << endl;
cout << testEmployee.getCommission() << endl;
}
CodePudding user response:
Parsing CSV file is an old topic. You will find at least 100 answers with code examples here on stackoverflow. Very often you will find a solution with the function std::getline
. Please read the documentation here. It can read characters from a std::ifstream
until or up to a delimiter (a comma ,
in our case), then store the result, without the comma, in a string and discard the comma from the stream. So, throwing that away. The characters will be stored in a std::string
. If numbers or other types are needed, we need to convert the string to the other type, using the appropriate function.
Example: We have a string consisting of characters ‘1’, ‘2’ and ‘3’, so, “123”. The quotes indicate the string type. If we want to convert this string into an integer, we can use for example the function std::stoi
.
In your case, you have 2 double values. So, we would split the input of the file into strings and then convert the 2 strings with the double values in it, using the function std::stod
.
What you need to know additionally is, that often a 2 step approach is used. This is done to prevent potential problems arising from extracting all the string parts from one csv line. So,
- we first read a complete line,
- then put that line into a
std::istringstream
, and finally - read input and split the CSV from there.
Then, the rest is simple. Just use std::getline
to al the data that you need.
Last but not least, to read the file, we will simply open it, read line by line, create an “EmployeeAccount” and push that into a std::vector
At the end we do some debug output.
Please see below one of may potential implementation proposals:
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
class EmployeeAccount {
private:
//member variable
std::string acountNumber;
std::string title;
std::string firstname;
std::string lastname;
std::string company;
std::string salesperson;
double purchaseValue;
std::string prev_salestaff;
double commission;
public:
//overload constructor
EmployeeAccount(const std::string& employeeAccountInfo)
{
std::istringstream employeeAccountStream(employeeAccountInfo);
std::getline(employeeAccountStream, acountNumber, ',');
std::getline(employeeAccountStream, title, ',');
std::getline(employeeAccountStream, firstname, ',');
std::getline(employeeAccountStream, lastname, ',');
std::getline(employeeAccountStream, company, ',');
std::getline(employeeAccountStream, salesperson, ',');
std::string temp;
std::getline(employeeAccountStream, temp, ',');
purchaseValue = std::stod(temp);
std::getline(employeeAccountStream, prev_salestaff, ',');
std::getline(employeeAccountStream, temp, ',');
commission = std::stod(temp);
}
//Access methods
std::string getAccountNumber() const { return acountNumber; };
std::string getTitle() const { return title; };
std::string getFirstname() const { return firstname; };
std::string getLastname() const { return lastname; };
std::string getCompany() const { return company; };
double getPurchaseValue() const { return purchaseValue; };
std::string getPrev_salesstaff() const { return prev_salestaff; };
double getCommission() const { return commission; };
std::string getAccountDetail() const { return acountNumber " " title " " firstname " " lastname " " company;};
//Destructor
~EmployeeAccount() {};
};
int main() {
std::ifstream ifs{ "accounts.txt" };
if (ifs) {
// Here we will store all accounts
std::vector<EmployeeAccount> accounts{};
// Read the file line by line
std::string line{};
while (std::getline(ifs, line)) {
// Create one account by splitting the input line
EmployeeAccount account(line);
// Add the new accounts to the vector of accounts
accounts.push_back(account);
}
// Debug output. For all accounts that we read, output all data
for (const EmployeeAccount& account : accounts) {
std::cout << "\n--------------------------\n"
<< account.getAccountDetail() << '\n'
<< account.getAccountNumber() << '\n'
<< account.getTitle() << '\n'
<< account.getFirstname() << '\n'
<< account.getLastname() << '\n'
<< account.getCompany() << '\n'
<< account.getPurchaseValue() << '\n'
<< account.getPrev_salesstaff() << '\n'
<< account.getCommission() << '\n';
}
}
else
std::cerr << "\n*** Error: Could not open source file\n\n";
}