Suppose we have the following situation:
struct Person {
unsigned int id;
std::st
Another solution is to require certain delimiter characters for a particular field, and provide a special extraction manipulator for this purpose.
Let's suppose we define the delimiter character ", and the input should look like this:
1267867 "John Smith" 32
67545 "Jane Doe" 36
8677453 "Gwyneth Miller" 56
75543 "J. Ross Unusual" 23
Generally needed includes:
#include
#include
#include
The record declaration:
struct Person {
unsigned int id;
std::string name;
uint8_t age;
// ...
};
Declaration/definition of a proxy class (struct) that supports being used with the std::istream& operator>>(std::istream&, const delim_field_extractor_proxy&) global operator overload:
struct delim_field_extractor_proxy {
delim_field_extractor_proxy
( std::string& field_ref
, char delim = '"'
)
: field_ref_(field_ref), delim_(delim) {}
friend
std::istream& operator>>
( std::istream& is
, const delim_field_extractor_proxy& extractor_proxy);
void extract_value(std::istream& is) const {
field_ref_.clear();
char input;
bool addChars = false;
while(is) {
is.get(input);
if(is.eof()) {
break;
}
if(input == delim_) {
addChars = !addChars;
if(!addChars) {
break;
}
else {
continue;
}
}
if(addChars) {
field_ref_ += input;
}
}
// consume whitespaces
while(std::isspace(is.peek())) {
is.get();
}
}
std::string& field_ref_;
char delim_;
};
std::istream& operator>>
( std::istream& is
, const delim_field_extractor_proxy& extractor_proxy) {
extractor_proxy.extract_value(is);
return is;
}
Plumbing everything connected together and instantiating the delim_field_extractor_proxy:
int main() {
std::istream& ifs = std::cin; // Open file alternatively
std::vector persons;
Person actRecord;
int act_age;
while(ifs >> actRecord.id
>> delim_field_extractor_proxy(actRecord.name,'"')
>> act_age) {
actRecord.age = uint8_t(act_age);
persons.push_back(actRecord);
}
for(auto it = persons.begin();
it != persons.end();
++it) {
std::cout << it->id << ", "
<< it->name << ", "
<< int(it->age) << std::endl;
}
return 0;
}
See the working example here.
NOTE:
This solution also works well specifying a TAB character (\t) as delimiter, which is useful parsing standard .csv formats.