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 ofstr
in the string, ornpos
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 positionpos
and of lengthnpos
.
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
Why Do People Say There Is Modulo Bias When Using a Random Number Generator
Why Have Header Files and .Cpp Files
When a Function Has a Specific-Size Array Parameter, Why Is It Replaced With a Pointer
Difference Between Public, Private, and Protected Inheritance in C++
What Does the Explicit Keyword Mean
Strange Output in Comparison of Float With Float Literal
Boost Spirit: "Semantic Actions Are Evil"
What's the Difference Between "Stl" and "C++ Standard Library"
Easiest Way to Convert Int to String in C++
How to Get the Cpu Cycle Count in X86_64 from C++
A Positive Lambda: '+[]{}' - What Sorcery Is This
Timer Function to Provide Time in Nano Seconds Using C++
How to Pass a Class Member Function as a Callback
Why Must a Short Be Converted to an Int Before Arithmetic Operations in C and C++
How to Add a Linker or Compile Flag in a Cmake File
How to Properly Overload the ≪≪ Operator For an Ostream
What Do Single Quotes Do in C++ When Used on Multiple Characters