Reputation: 3716
I am parsing an array of text that come from "C-only" interface and where each string may have an arbitrary amount of values that may, isolatedly, be parsed by a "istream::operator >>()
".
For example, one of the parsers is for a custom IPv4 class:
std::istream & operator >>( std::istream& stream, IPv4 &var )
The implementation is quite obvious.
Now suppose an input like:
const char *string_array[] =
{
"192.168.0.1, 192.168.0.32, 192.168.0.40",
"169.254.3.18, 169.254.3.19, 169.254.3.20, 169.254.3.21",
"10.0.92.100",
"10.0.0.101, 10.0.0.102, 10.0.0.103 , 10.0.0.104 , 10.0.0.110 ",
};
I'd like to find an elegant way to put all of the parsed values in an array so that I can send it to "C-only" functions.
The naive way would be first contatening all of the strings (const char *
) with a stringstream
and then loop over this stream with my operator >>
.
std::stringstream ss;
IPv4 ip;
std::vector< IPv4 > ip_vector;
for ( int c = 0; c < count; ++c )
ss << string_array[ c ] << ", ";
while ( ss.good( ) )
{
ss >> ip;
ip_vector.push_back( ip );
}
It seems not that wise to me, but I can't figure out how to make this smarter.
Note also: Boost is not an option for this solution.
Upvotes: 1
Views: 269
Reputation: 226
std::copy()
and std::back_inserter
is surely the way out.
I'd stick, though with the for
loop for iterating through the strings instead of concatenating everything in a stringstream
, as suggested by @ephemient:
std::vector< IPv4 > ip_vector;
for ( unsigned c = 0; c < count; ++c )
{
std::stringstream ss( string_array[ c ] );
std::copy( std::istream_iterator< IPv4 >( ss ), std::istream_iterator< IPv4 >( ),
std::back_inserter( ip_vector ) );
}
This way you make clear you are transforming all the strings.
You also have to construct 3 std::stringstream
objects, but won't have to relocate memory for concatenating strings.
Upvotes: 1
Reputation: 60014
I think that concatenating it's useless: simply 'join' the loops, something like:
istream &skipblanks(istream &s) {
char c;
while ((c = s.peek()) == ' ' || c == ',')
s.get();
return s;
}
...
std::vector< IPv4 > ip_vector;
for ( int c = 0; c < count; ++c ) {
istringstream ss(string_array[ c ]);
while (ss) {
IPv4 ip;
if (skipblanks(ss) >> ip)
ip_vector.push_back( ip );
}
}
Upvotes: 1
Reputation: 204718
There's built-in STL functionality that you can use instead of writing your own loops.
copy(string_array, string_array + count,
ostream_iterator<const char *>(ss, ", "));
copy(istream_iterator<IPv4>(ss), istream_iterator<IPv4>(),
back_inserter(ip_vector));
Upvotes: 2