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
Deleting Elements from Std::Set While Iterating
Constants and Compiler Optimization in C++
How to Link C++ Program With Boost Using Cmake
Writing Bmp Image in Pure C/C++ Without Other Libraries
What Happens in a Double Delete
Is There Any Real Risk to Deriving from the C++ Stl Containers
Removing Item from Vector, While in C++11 Range 'For' Loop
How to Increase the Re-Usability of This Key-Oriented Access-Protection Pattern
Lock-Free Progress Guarantees in a Circular Buffer Queue
Copying a Polymorphic Object in C++
C++ Function Template Partial Specialization
C++: Print Out Enum Value as Text
Is Pass-By-Value a Reasonable Default in C++11