How to Use Non-Default Delimiters When Reading a Text File with Std::Fstream

How can I use non-default delimiters when reading a text file with std::fstream?

An istream treats "white space" as delimiters. It uses a locale to tell it what characters are white space. A locale, in turn, includes a ctype facet that classifies character types. Such a facet could look something like this:

#include <locale>
#include <iostream>
#include <algorithm>
#include <iterator>
#include <vector>
#include <sstream>

class my_ctype : public
std::ctype<char>
{
mask my_table[table_size];
public:
my_ctype(size_t refs = 0)
: std::ctype<char>(&my_table[0], false, refs)
{
std::copy_n(classic_table(), table_size, my_table);
my_table['-'] = (mask)space;
my_table['\''] = (mask)space;
}
};

And a little test program to show it works:

int main() {
std::istringstream input("This is some input from McDonald's and Burger-King.");
std::locale x(std::locale::classic(), new my_ctype);
input.imbue(x);

std::copy(std::istream_iterator<std::string>(input),
std::istream_iterator<std::string>(),
std::ostream_iterator<std::string>(std::cout, "\n"));

return 0;
}

Result:

This
is
some
input
from
McDonald
s
and
Burger
King.

istream_iterator<string> uses >> to read the individual strings from the stream, so if you use them directly, you should get the same results. The parts you need to include are creating the locale and using imbue to make the stream use that locale.

Reading File through ifstream with delimiters

You missed std::list<ItemData> itemsList; from your code.

#include <iostream>
#include <string>
#include <fstream>
#include <string>
#include <vector>

struct ItemData {
int ID;
std::string name;
std::string description;
};

std::vector<ItemData> itemsList;

void GetItemData() {
std::ifstream File("items.txt");
std::string TempString;
while (File.good()) {
ItemData itemData;
getline(File, TempString);
size_t pos = TempString.find('-');
itemData.ID = stoi(TempString.substr(0, pos));
size_t pos2 = TempString.find('-', pos + 1);
itemData.name = TempString.substr(pos + 1, pos2 - (pos + 1));
itemData.description = TempString.substr(pos2 + 1, TempString.length() - 1);
itemsList.push_back(itemData);
}
}

std::ostream& operator<<(std::ostream& os, const ItemData& item) {
os << item.ID << " - " << item.name << " - " << item.description;
return os;
}

void PrintFile() {
GetItemData();
std::ofstream file("out.txt");
for(auto line : itemsList) {
file << line << std::endl;
}
}

int main() {
PrintFile();
return 0;
}

I debug the code and it words for me, if this does not work for you, something else went wrong.

How to read text file with multiple delimiter?

You can read and discard the | with:

std::stringstream ss(line);
int a, b; double c;
char s;
if (ss >> a >> s >> b >> s >> c)
{
data.push_back(std::tuple<int, int, double>(a, b, c));
}

Reading objects into an array from a text file with space delimiter

The function operator>>(ifstream& in, rational& r) should work as posted although I would change it to

std::istream& operator>>(std::istream& in, rational& r) { ... }

However, the first function is not right. You are not returning anything from the function even though its return type is int. You can change it to:

int operator>>(ifstream& fin, rational r[])
{
int count = 0;
fin.open("filedata.txt", ios::in);
if (fin)
{
for ( ; count < 5; ++count)
{
// If unable to read, break out of the loop.
if ( !(fin >> r[count] )
{
break;
}
}
}
else
{
cout << "\nData file cannot be found!" << endl;
}
return count;
}

Having said that, I think you can improve that function a bit.

  1. Open the file in the calling function, main maybe, and pass the std::ifstream object to it.

  2. Instead of passing it an array, pass it a std::vector. Then, you don't have worry about the number of entries in the file. You read whatever you can find in the file.

  3. Change the return type to be std::istream& so you can chain the calls if necessary.

std::istream& operator>>(std::istream& in, std::vector<rational>& v)
{
rational r;
while ( in >> r )
{
v.push_back(r);
}
return in;
}

In main (or whichever is the higher level function), use:

std::vector<rational> v;
std::ifstream fin("filedata.txt);
if ( !fin )
{
// Deal with error.
}
else
{
fin >> v;
}

// Use v as you see fit.

How to extract string with comma delimiter from txt file and parse every element separete by comma delimiter into a class constructor

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";
}



Related Topics



Leave a reply



Submit