1

I have looked at the previous questions to find the best way to look for a floating point value. My problem is I have a line that should contain at least 3 floating point values in addition to some other text. I want to extract the first three floating point values from the line and use them. However, I can only get boost::regex to give me the first value. What am I doing wrong? I do want to force at least one digit on each side of the decimal and force that a decimal must exist as well.

My example input string is

"this is a name" 39.789876 -83.997978 30.000000

My code looks like

std::string line = "\"this is a name\" 39.789876 -83.997978 30.000000";
static boost::regex llhNums_regex = boost::regex("[-]?[0-9]+[.][0-9]+");
boost::smatch resultsTwo;
if(boost::regex_search(line, resultsTwo, llhNums_regex))
{
    std::cout << "Found results\n";
}
for(int i = 0 ; i<resultsTwo.size() ; ++i)
{
    std::cerr << i << ": " << resultsTwo[i].str() << std::endl;
}

Yet resultsTwo.size() is only 1 and it prints out just the first floating point value. How do I get all three values out? I am sure there is something basic with regular expressions I am misunderstanding, but I cannot figure it out.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Todd
  • 90
  • 6
  • For a direct answer to the Regex question: https://stackoverflow.com/questions/3122344/boost-c-regex-how-to-get-multiple-matches?noredirect=1&lq=1 – sehe Aug 09 '17 at 21:36

1 Answers1

1

I think you're using the wrong tool for the job. If you want a parser, use a parser.

After all you want to parse the data. There are many valid formats for real numbers (what about positive signs, scientific notation, NaN and infinity?). You want to have the correctly converted data, not the string values.

You may even want to have the name or reliably skip it, even if the name contains a number (OOOPS).

So, here's a simple approach using Boost Spirit:

Live On Wandbox

#include <iostream>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;

bool parse_line(std::string const& line, std::string& name, double& a, double& b, double& c) {
    using It = std::string::const_iterator;
    qi::rule<It, std::string()> quoted = '"' >> *~qi::char_('"') >> '"';

    It f = line.begin(), l = line.end();
    return qi::phrase_parse(f, l, quoted >> qi::double_ >> qi::double_ >> qi::double_, qi::blank, name, a, b, c);
}

int main() {
    std::string name;
    double a, b, c;

    if (parse_line("\"this is a name\" 39.789876 -83.997978 30.000000", name, a, b, c)) {
        std::cout << "Parsed: \n"
            << " Name '" << name << "'\n"
            << " (a,b,c): (" << a << ", " << b << ", " << c << ")\n";
    }
}

Prints:

Parsed:
 Name 'this is a name'
 (a,b,c): (39.7899, -83.998, 30)
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks this worked perfectly and I do think this is better than my regular expression although I did not need to worry about handling various forms of floating point numbers. – Todd Aug 11 '17 at 14:40