Parsing a Comma-Delimited Std::String

Parsing a comma-delimited std::string [duplicate]

Input one number at a time, and check whether the following character is ,. If so, discard it.

#include <vector>
#include <string>
#include <sstream>
#include <iostream>

int main()
{
std::string str = "1,2,3,4,5,6";
std::vector<int> vect;

std::stringstream ss(str);

for (int i; ss >> i;) {
vect.push_back(i);
if (ss.peek() == ',')
ss.ignore();
}

for (std::size_t i = 0; i < vect.size(); i++)
std::cout << vect[i] << std::endl;
}

Split comma separated string [duplicate]

Try this snippet:

int main()
{
vector<string> sentences =
{ "A1,John,Smith,smithJ@mail.com,42",
"B2,Jane,Doe,jd@gmailcom,121,2",
"C3,Mickey,Mouse,mouseman@mail.com,20"
};

vector<string> results;

for (auto words : sentences) {
stringstream ss(words);
string str;
while (getline(ss, str, ',')) {
results.push_back(str);
}
}

//display result
for (auto word : results) {
cout << word << '\n';
}

return 0;
}

Parse comma-separated ints/int-ranges in C++

Apart from @J. Schultke's excellent example, I suggest the use of regexes in the following way:

#include <algorithm>
#include <iostream>
#include <regex>
#include <string>
#include <vector>

void process(std::string str, std::vector<int>& num_vec) {
str.erase(--str.end());
for (int i = str.front() - '0'; i <= str.back() - '0'; i++) {
num_vec.push_back(i);
}
}

int main() {
std::string str("1,2,3,5-6,7,8");
str += "#";
std::regex vec_of_blocks(".*?\,|.*?\#");
auto blocks_begin = std::sregex_iterator(str.begin(), str.end(), vec_of_blocks);
auto blocks_end = std::sregex_iterator();
std::vector<int> vec_of_numbers;
for (std::sregex_iterator regex_it = blocks_begin; regex_it != blocks_end; regex_it++) {
std::smatch match = *regex_it;
std::string block = match.str();
if (std::find(block.begin(), block.end(), '-') != block.end()) {
process(block, vec_of_numbers);
}
else {
vec_of_numbers.push_back(std::atoi(block.c_str()));
}
}
return 0;
}

Of course, you still need a tad bit validation, however, this will get you started.

Parsing function for comma-delimited string

The following is a basic CSV parser:

void readCSVline(char *line);
char *readCSVfield(char *line, char *buf);
void readCSVdemo(void)
{
char line[]= "0,,10004,10004,\"Albany Hwy After Galliers Av\",\"\",-32.13649428,116.0176090070,3";
readCSVline(line);

}
/* readCSVline is where you put your "intelligence" about fields to read
* and what to do with them
*/
void readCSVline(char *line)
{
char field1[80], *lineptr=line;
int nfields=0;

while (*lineptr) {
lineptr= readCSVfield(lineptr, field1);
printf("%s\n", field1);
nfields++;
}
printf("%d fields read.\n", nfields);
}
/* readCSVfield reads a field from a CSV line until the next comma or end-of-line.
* It returns where the reading stopped.
*/
char *readCSVfield(char *line, char *buf)
{
int instr= FALSE; // track whether we are in a string
char *cptr= line;

while (*cptr)
{
if (instr) {
if (*cptr=='"') {
char cc= *++cptr;
if (cc=='"') // escaped double quote
*buf++ = '"';
else {
*buf='\0';
cptr--;
instr= FALSE;
}
}
else *buf++ = *cptr;
}
else switch (*cptr) {
case '"': instr= TRUE; break;
case ',': cptr++; *buf= '\0'; return(cptr);
case ' ': case '\t': case '\n': case '\r': break;
default: *buf++ = *cptr;
}
cptr++;
}
*buf= '\0';
return(cptr);
}

Parse (split) a string in C++ using string delimiter (standard C++)

You can use the std::string::find() function to find the position of your string delimiter, then use std::string::substr() to get a token.

Example:

std::string s = "scott>=tiger";
std::string delimiter = ">=";
std::string token = s.substr(0, s.find(delimiter)); // token is "scott"
  • The find(const string& str, size_t pos = 0) function returns the position of the first occurrence of str in the string, or npos if the string is not found.

  • The substr(size_t pos = 0, size_t n = npos) function returns a substring of the object, starting at position pos and of length npos.


If you have multiple delimiters, after you have extracted one token, you can remove it (delimiter included) to proceed with subsequent extractions (if you want to preserve the original string, just use s = s.substr(pos + delimiter.length());):

s.erase(0, s.find(delimiter) + delimiter.length());

This way you can easily loop to get each token.

Complete Example

std::string s = "scott>=tiger>=mushroom";
std::string delimiter = ">=";

size_t pos = 0;
std::string token;
while ((pos = s.find(delimiter)) != std::string::npos) {
token = s.substr(0, pos);
std::cout << token << std::endl;
s.erase(0, pos + delimiter.length());
}
std::cout << s << std::endl;

Output:

scott
tiger
mushroom

Parsing integer from comma delimited string

1) Conditional statement.

std::stringstream derives from std::ios, which defines:

  • In C++ 98 / C++ 03: operator void*() const

Description: A null pointer if at least one of failbit or badbit is set. Some other value otherwise.

  • In C++ 11: explicit operator bool() const

Description: true if none of failbit or badbit is set. false otherwise.

That's why you can use this expression as condition for a loop - operator>> returns reference to stringstream object, which then is converted to either void* pointer or bool, depending on supported C++ version.

More info about this: std::ios::operator bool

2) operator>> applied for numbers extracts as many characters as it can:

int main()
{
std::string str = "111,12,1063,134,10005,1226";
std::vector<int> vect;

std::stringstream ss(str);

int i;

while (ss >> i)
{
vect.push_back(i);

if (ss.peek() == ',')
ss.ignore();
}

return 0;
}

Content of vector: [111, 12, 1063, 134, 10005, 1226].

Again, more info: std::istream::operator>>

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