Re: Parsing (a Series of) Variables
Rui Maciel <rui.maciel@gmail.com> writes:
It looks like a job for a proper parser. Any solution which can be pulled
together with sscanfs and the sort will inevitable be broken and fallible.
The following code uses a simplistic parser to parse numbers from
"1 2. .3 4"
into a heterogenous target, so that
for( numval * v : target )
::std::cout << static_cast< ::std::string >( *v )<< '\n';
prints
( int )1
( double )2.000000
( double )0.300000
( int )4
and
double sum = 0; for( numval * v : target )sum += *v;
::std::cout << sum << '\n';
prints
7.3
. I am not sure whether my use of dynamic_cast is correct since it's
the first time that I actually used it.
#include <iostream>
#include <ostream>
#include <sstream>
#include <vector>
#include <cstdio>
#include <cctype>
#include <string>
struct numval
{ virtual ::std::string text() const = 0;
virtual operator ::std::string() const = 0;
virtual operator double() const = 0;};
struct intval : public numval
{ int val;
intval( ::std::string & text )
{ val = ::std::stoi( text ); }
virtual operator double() const
{ return this->val; }
virtual operator ::std::string() const
{ return text(); }
::std::string text() const
{ ::std::string s;
s += "( int )";
s += ::std::to_string( this->val );
return s; }};
struct doubleval : public numval
{ double val;
doubleval( ::std::string & text )
{ val = ::std::stod( text ); }
virtual operator double() const
{ return this->val; }
virtual operator ::std::string() const
{ return text(); }
::std::string text() const
{ ::std::string s;
s += "( double )";
s += ::std::to_string( this->val );
return s; }};
numval * new_numval
( bool point, ::std::string & text )
{ return point ? dynamic_cast< numval * >( new doubleval( text )):
dynamic_cast< numval * >( new intval( text )); }
void numeral
( ::std::stringstream & source,
::std::string & seen,
::std::vector<numval *> & target )
{ int c;
bool looping = true;
bool point = false;
while( looping )
{ c = source.peek();
if( c == EOF )looping = false; else
if( isdigit( c ))seen.push_back( source.get() );
else if( c == '.' )
{ if( point )looping = false; else
{ point = true; seen.push_back( source.get() ); }}
else looping = false; }
if( seen == "." )seen.push_back( '0' );
target.push_back( new_numval( point, seen ));
seen.clear(); }
void other
( ::std::stringstream & source,
::std::string & seen,
::std::vector<numval *> & target )
{ int c = source.peek();
while( !( isdigit( c )|| c == '.' ))
{ seen.push_back( source.get() );
c = source.peek(); }
seen.clear(); }
int main()
{ ::std::stringstream source{ "1 2. .3 4" };
::std::string seen;
::std::vector<numval *> target;
int c; do
{ c = source.peek();
if( isdigit( c ) || c == '.' )numeral( source, seen, target );
else other( source, seen, target ); }
while( source.good() );
for( numval * v : target )
::std::cout << static_cast< ::std::string >( *v )<< '\n';
double sum = 0;
for( numval * v : target )sum += *v;
::std::cout << sum << '\n'; }