Using Stringstream: Only works for the first value

advertisements

I am trying to use stringstream with peek() and get(n). It is only working for the first value, Name, and then gives empty values for everything except weight, which gives 0 (when printing out with cout).

    stringstream ss;
    ss.str("John Smith, Toyota, 160, brown blue, orange");
    //Extract into these variables:
    string Name = "" ;
    string car = "" ;
    int weight = 0;
    string hairColor = "";
    string eyeColor = "";
    string favoriteColor = "";

while (ss.peek () != ',')
        {
            char temp;
            ss. get(temp);
            Name += temp;
        }
while (ss.peek () != ',')
        {
            char temp;
            ss. get(temp);
            car += temp;
        }
while (ss.peek () != ',')
        {
            char temp;
            ss. get(temp);
            weight += temp;
        }
while (ss.peek () != ',')
        {
            char temp;
            ss. get(temp);
            hairColor += temp;
        }
while (ss.peek () != ',')
        {
            char temp;
            ss. get(temp);
            eyeColor += temp;
        }
while (ss.peek () != ',')
        {
            char temp;
            ss. get(temp);
            favoriteColor += temp;
        }

cout << "Name is: " << Name << endl;
cout << "car is: " << car << endl;
cout << "weight is: " << weight << endl;
cout << "Hair color is: " << hairColor << endl;
cout << "Eye color is: " << eyeColor << endl;
cout << "Favorite color is: " << favoriteColor << endl;

What is the problem here?


The immediate problem is that after the first loop the continuation condition is false, so none of the following loops, with the same continuation condition, do anything.

However, the usual way to extract an item is to use the getline function, where you can specify an arbitrary delimiter character instead of newline.

Doing this properly is a bit involved:

#include <iomanip>              // std::setw
#include <iostream>
#include <stdexcept>            // std::runtime_error, std::exception
#include <stdlib.h>             // EXIT_FAILURE, EXIT_SUCCESS
#include <sstream>              // std::istringstream
using namespace std;

auto fail( const string& s ) -> bool { throw runtime_error( s ); }

auto get_string( istream& stream, const char delimiter = ',' )
    -> string
{
    while( stream.peek() == ' ' )
    {
        stream.get();
    }
    string result;
    getline( stream, result, delimiter )
        || fail( "get_string: failed to extract text" );
    return result;
}

template< class Type >
auto get( istream& stream, const char delimiter = ',' )
    -> Type
{
    istringstream conversion_stream( get_string( stream, delimiter ) );
    Type result;
    conversion_stream >> result
        || fail( "get: failed to convert text to value" );
    return result;
}

template<>
auto get<string>( istream& stream, const char delimiter )
    -> string
{ return get_string( stream, delimiter ); }

template< class Type >
void display( const char name[], const Type& value )
{
    cout << setw( 15 ) << name << " = " << value << endl;
}

#define DISPLAY( x ) display( #x, x )
void cpp_main()
{
    istringstream data_stream( "John Smith, Toyota, 160, brown, blue, orange" );

    const auto name             = get<string>( data_stream );
    const auto car              = get<string>( data_stream );
    const auto weight           = get<int>( data_stream );
    const auto hairColor        = get<string>( data_stream );
    const auto eyeColor         = get<string>( data_stream );
    const auto favoriteColor    = get<string>( data_stream );

    DISPLAY( name );
    DISPLAY( car );
    DISPLAY( weight );
    DISPLAY( hairColor );
    DISPLAY( eyeColor );
    DISPLAY( favoriteColor );
}

auto main() -> int
{
    try
    {
        cpp_main();
        return EXIT_SUCCESS;
    }
    catch( const exception& x )
    {
        cerr << "!" << x.what() << endl;
    }
    return EXIT_FAILURE;
}