j4x
j4x

Reputation: 3716

C++ better way to parse values into a vector

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

Answers (3)

JaxWR
JaxWR

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

CapelliC
CapelliC

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

ephemient
ephemient

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

Related Questions