C++ alternative for parsing input with sscanf

I you can afford to use boost, you could use Spirit.

See

  • From a string Live On Coliru (in c++03):

  • Update And here's the approach if you were actually trying to read from a stream (it's actually somewhat simpler, and integrates really well with your other stream reading activities):
    Live On Coliru too (c++03)

Allthough this seems more verbose, Spirit is also a lot more powerful and type-safe than sscanf. And it operates on streams.

Also note that inf, -inf, nan will be handled as expected.

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_match.hpp>
#include <sstream>

namespace qi = boost::spirit::qi;

int main()
{
    std::istringstream ss("[ 0.562 , 1.4e-2 ]"); // example input
    ss.unsetf(std::ios::skipws); // we might **want** to handle whitespace in our grammar, not needed now

    float f1 = 0.0f, f2 = 0.0f;

    if (ss >> qi::phrase_match('[' >> qi::double_ >> ',' >> qi::double_ >> ']', qi::space, f1, f2))
    {
        std::cout << "Parsed: " << f1 << " and " << f2 << "\n"; // default formatting...
    } else
    {
        std::cout << "Error while parsing" << std::endl;
    }
}

The obvious approach is to create a simple manipulator and use that. For example, a manipulator using a statically provided char to determine if the next non-whitespace character is that character and, if so, extracts it could look like this:

#include <iostream>
#include <sstream>

template <char C>
std::istream& expect(std::istream& in)
{
    if ((in >> std::ws).peek() == C) {
        in.ignore();
    }
    else {
        in.setstate(std::ios_base::failbit);
    }
    return in;
}

You can then use the thus build manipulator to extract characters:

int main(int ac, char *av[])
{
    std::string s(ac == 1? "[ 0.562 , 1.4e-2 ]": av[1]);
    float f1 = 0.0f, f2 = 0.0f;

    std::istringstream in(s);
    if (in >> expect<'['> >> f1 >> expect<','> >> f2 >> expect<']'>) {
        std::cout << "read f1=" << f1 << " f2=" << f2 << '\n';
    }
    else {
        std::cout << "ERROR: failed to read '" << s << "'\n";
    }
}

Tags:

C++

Parsing

Scanf