How to Use Stringstream to Separate Comma Separated Strings

How to use stringstream to separate comma separated strings

#include <iostream>
#include <sstream>

std::string input = "abc,def,ghi";
std::istringstream ss(input);
std::string token;

while(std::getline(ss, token, ',')) {
std::cout << token << '\n';
}

abc

def

ghi

Stringstream Delimiter

There is no "delimiter" for streams at all. operator>>, on the other hand, implements its reading by delimiting on whitespace characters. For other delimiter characters, you can use std::getline() instead, eg:

vector<int> parseInts(string str) {
// Complete this function
istringstream iss(str);
vector<int> res;
int x;
string temp;
char delim = '-'; // whatever you want
while (getline(iss, temp, delim)) {
if (istringstream(temp) >> x) { // or std::stoi(), std::strtol(), etc
res.push_back(x);
}
}
return res;
}

This code works without me mentioning any specific delimiter. How does that happen?

streams don't know anything about delimiters. What is happening is that, on each loop iteration, you are calling ss >> x to read the next available non-whitespace substring and convert it to an integer, and then you are calling ss >> ch to read the next available non-whitespace character following that integer. The code doesn't care what that character actually is, as long as it is not whitespace. Your loop runs until it reaches the end of the stream, or encounters a reading/conversion error.

stringstream in c++ helps to extract comma separated integers from string but not space separated integers using vectors,why?

Because formatted input operations skip whitespaces. Thus the following happens:

ss >> num // reads integer 1
>> ch; // skips whitespace after 1 and reads char '2'

In the next iteration:

ss >> num // skips whitespace after 2 and reads integer 3
>> ch; // skips whitespace after 3 and reads char '4'

And the last iteration:

ss >> num // skips whitespace after 4 and reads integer 5
>> ch; // Encounters eof, nothing is read

Don't read that char for space-seperated lists. Or You can use std::noskipws to change this behaviour.

Splitting a stringstream that contains comma separated entries

The istream >> operator when applied to a string discards the eventual initial spaces and reads up to the first "space".

It works the same for whatever type (including int). It works in your code because at the ',' the "int reader" fails, and assumes the following is something else.

The simplest way to read comma separated strings is using the std::getline function, giving a ',' as a separator.

In your case, your template function

template <typename T>
std::istream &operator>>(std::istream &is, Array<T> &t)
{ ...... }

remains valid, but requires a specialization

std::istream &operator>>(std::istream &is, Array<std::string> &t)
{
std::string r;
while(std::getline(is,r,','))
t.push_back(r);
return is;
}

Stringstream delimeter

You cannot specify a delimiter with operator>>. Use std::getline() to read a delimited value into a temp std::string, then use a std::istringstream to parse the string.

void foo(const std::string& csvline)
{
std::istringstream csvStream(csvline);
std::string s, tmp;
int i1, i2;
double d;

std::getline(csvStream, s, ',');

std::getline(csvStream, tmp, ',');
std::istringstream(tmp) >> i1;

std::getline(csvStream, tmp, ',');
std::istringstream(tmp) >> i2;

std::getline(csvStream, tmp);
std::istringstream(tmp) >> d;
}

comma separated stringstream error. it also separates '-'

In order to solve the problem you need to do == this occurs on if (colA = 0) which should be if (colA == 0)

Hope this helps

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