I'm trying to read in a file with personal information. Each line contains the data of one person, let's say it looks like this:
First(s) Last ID SSN
Peter Barker 1234 5678
James Herbert Bond 007 999
Barack Hussein Obama 2007 14165
So I want to use std::copy
to read each line and copy it in a (std::vector<Person>
) like this:
struct Person
{
std::string firstName_s;
std::string lastName;
int ID;
int SSD;
}
I thought that it would be handy to overload the extraction operator for this:
std::istringstream& operator>>(std::istringstream& in, struct Person& person)
{
struct Person tmp;
in >> tmp.firstName_s
>> tmp.lastName
>> tmp.ID
>> tmp.SSN;
person = std::move(tmp);
return in;
}
However, the problem I'm having is that I do not know how many first names the person will have.
I thought about reading the full name into one string until I encounter a number and them split the last name from the string containing the first name(s), this worked fine but looks 'ugly'. It would be great if someone had a better suggestion, or a link I could look at, I can't seem to find something on my own! Thank you.
If you have a variable length line (in terms of word count) you can simply read the entire line and either process it from the right, or cache all words and work with offsets. The example below does the latter one.
int to_int(std::string_view str)
{
int val = 0;
std::from_chars(str.data(), str.data() + str.size(), val);
return val;
}
std::istream& operator>>(std::istream& in, Person& person)
{
std::string line;
// read whole line
if (std::getline(in, line))
{
// split line into words
std::vector<std::string> words;
std::stringstream tmp_stream(line);
for (std::string word; tmp_stream >> word; )
words.push_back(word);
// join first names
tmp_stream.str(words[0]);
for (std::size_t i = 1; i < words.size() - 3; i++)
tmp_stream << ' ' << words[i];
person.firstName_s = tmp_stream.str();
person.lastName = words[words.size() - 3];
person.ID = to_int(words[words.size() - 2]);
person.SSN = to_int(words[words.size() - 1]);
}
return in;
}
I think the code is self-explanatory. Here is a full example.