2

i am working on simple program and have stuck with this for a few days now.

How to parse integers (and possibly doubles) from character array? If it would be easier, char array can be converted to string, i mean, it is not a must have char array.

I was looking for a C++ way of

sscanf(mystring, "di %lf %lf %lf", &d1, &d2, &d3);

Problem is, i will have multiple lines of unknown length (numbers). And i'll have spaces or commas or something else delimiting numbers.

Are tokens the way? Of which i know nothing.

Well, thanks for any help.

Alexander Gessler
  • 45,603
  • 7
  • 82
  • 122
Martin Berger
  • 1,639
  • 3
  • 18
  • 39
  • 1
    have a look at this question and all the answers therein: http://stackoverflow.com/questions/53849/how-do-i-tokenize-a-string-in-c – Nim Apr 13 '11 at 13:46
  • 1
    http://stackoverflow.com/questions/5290089/how-to-convert-a-number-to-string-and-vice-versa-in-c has lots of info – Mat Apr 13 '11 at 13:47
  • @Mat All right, i have worked through that page, it took me 1.5 hours, but unfortunately that is not what i need. I have an character array (C-style 'char *' or C++ 'string') from which i need numbers. Thanks anyway. – Martin Berger Apr 14 '11 at 14:21
  • I am basing my own solution on this http://www.codeguru.com/forum/archive/index.php/t-180651.html – Martin Berger Apr 27 '11 at 13:53

3 Answers3

0

Simple C++ parsers usually look something like this…

struct syntax_error : std::runtime_error {
    syntax_error( char const *str ) : std::runtime_error( str ) {}
};

std::istringstream iss( str ); // str is char*; use str.c_str() for std::string

std::string opcode;
long double args[ args_max ];

iss >> opcode; // read up to whitespace

for ( size_t arg_cnt = 0; arg_cnt < arg_counts[ opcode ]; ++ arg_cnt ) {
    if ( iss >> args[ arg_cnt ] ) { // read number, discard preceding whitespace
        throw syntax_error( "too few args" );
    }

    char delim;
    if ( ! ( iss >> delim ) || delim != ',' ) {
        throw syntax_error( "expected ',' delimiter" );
    }
}
Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
0

I'm not too sure what you really need. It sounds like you don't know the exact format of your file. (You've certainly not described anything "exact".) To convert integers or doubles from a string, you should to use istringstream. If you want to support a variety of separators, you could easily write a manipulator to do it, something like:

class skipSeparators
{
    std::string mySeparators;
public:
    skipSeparators( std::string const& separators )
        : mySeparators( separators )
    {
    }
    friend std::ostream&
    operator>>(
        std::ostream& source,
        SkipSeparators const& manip )
    {
        source >> std::ws;
        int next = source.peek();
        if ( next != EOF
                && std::find( mySeparators.begin(),
                              mySeparators.end(),
                              static_cast<char>( next ) 
                            ) != mySeparators.end() ) {
            source.get();
        }
        return source;
    }
};

With this, you could write something like:

while ( input >> skipSeparators( ",;" ) >> someDouble ) {
    //  process some double...
}

If knowing where the line ends were important, you can read the file using getline(), and create an istringstream for each line, using the above on it.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Sorry for not being clear. I have win32 edit control from which i extract lines with function `GetWindowText (hwndEdit1, szBuffer, 100);`. As soon as i get the line i need numbers from it. And thanks for reply. – Martin Berger Apr 15 '11 at 09:50
  • I cant get skipSeparators to work. These are the headers included: `#include #include #include #include #include #include `, and `source >> std::ws;`, `source.peek();`, `mySeparators.begin()`, `source.get();` report errors... – Martin Berger Apr 15 '11 at 09:51
  • 1
    For starters, I clearly mistyped: all occurances of `ostream` should be `istream`. Which would account for the compiler not finding any of the functions on `source`. It should find `mySeparators.begin()`, however, if you've included `` (and if you didn't, it should complain about the declaration s of `mySeparators`). – James Kanze Apr 15 '11 at 11:48
  • Ok, corrected ostream to istream, that's good now. But, `begin()` and `end()` are still complaining: `error C2228: left of '.begin' must have class/struct/union` and `error C2228: left of '.end' must have class/struct/union`. MSDN says that begin() belongs to basic_sting: `basic_string::begin` and you get it with `` header. These are included: `#include #include #include #include #include #include `. I'll go to see if i can dig something about those errors. James, thanks for taking time to write that code. – Martin Berger Apr 15 '11 at 14:23
  • Nothin here on error: http://msdn.microsoft.com/en-us/library/3y365xw6(v=VS.90).aspx – Martin Berger Apr 15 '11 at 14:41
0

Take a look at Boost's lexical_cast, I think it does exactly what you want. Example from link:

int main(int argc, char * argv[])
{
    using boost::lexical_cast;
    using boost::bad_lexical_cast;

    std::vector<short> args;

    while(*++argv)
    {
        try
        {
            args.push_back(lexical_cast<short>(*argv));
        }
        catch(bad_lexical_cast &)
        {
            args.push_back(0);
        }
    }
    ...
}
drrlvn
  • 8,189
  • 2
  • 43
  • 57