1

I want to parse a lot of Lat/Long coordinates with the following format 1.123456W or 50.123456N, basically a double followed by a char ('N', 'S', 'W', 'E'). I just want to remove the character from the string, convert to double and change the sign if its W-est or S-outh. The following code works in three out of four cases:

This works for 1.123456W, or 50.123456N, or 9.123456S, but not for 7.123456E. I'm guessing the Qi parser expects an E at the input string to correlate with an exponent representation of a double and fails because its incomplete? But how do I tell Qi to skip the exponent if it fails an just decodes the string to the point of where the E resides?

double d;
char c;
auto const expr = boost::spirit::qi::double_ >> boost::spirit::qi::char_;
std::string tok = "7.123456E";
bool success = boost::spirit::qi::parse( tok.cbegin(), tok.cend(), expr, d, c ) ) {
if( success ) {
    if( c == 'W' || c == 'w' || c == 'S' || c == 'S' ) {
        d = -d;
    }
    /// ....
}

Thank you very much!

Hhut
  • 1,128
  • 1
  • 12
  • 24
  • 2
    I haven't used this part of the library before so I am going to leave it to someone else do create a definitive result. The first place I looked was http://www.boost.org/doc/libs/1_41_0/libs/spirit/doc/html/spirit/qi/reference/numeric/real.html. In the RealPolicies section, there's a grammar listing for real numbers. It looks to me as if what you're doing SHOULD work, as there are no actual digits that could be parsed as an exponent value, and so the exponent_part rule should fail. What version of boost are you using? Also, check out RealPolicies as that will provide a solution. – FatalFlaw Apr 16 '14 at 14:22
  • 1
    Also, you'll want to change one of those capital Ss to a small s. – FatalFlaw Apr 16 '14 at 14:23
  • Thank you. Although I haven't really understood how I can adjust the Real Parser Policies to remove this detection. And I have tried all possible characters... it's just the char `'E'` or `'e'`. It works for example if I change the input token to `7.123456E0E` —then it will get parsed correctly into `7.123456` and `'E'`. But that is not really an option. Is is possible to parse backwards? First parse the character at the end I with the rest trying parsing it to double? Thanks! – Hhut Apr 17 '14 at 06:36
  • ...and using Boost v1.49.0 – Hhut Apr 17 '14 at 06:46

1 Answers1

2

Here you go. The Coliru compiler didn't like your use of auto, so I made a minimal change to fix it.

Have a look at the RealPolicies documentation I supplied above. You create a new policy class based on the ureal_policies template, override the exponent-related methods and return false from them.

#include <iostream>
#include <boost/spirit/include/qi.hpp>

using namespace std;

//create a real number parser policy that doesn't handle exponent notation
template <typename T>
struct no_exp_policy : boost::spirit::qi::ureal_policies<T>
{
    //  No exponent
    template <typename Iterator>
    static bool
    parse_exp(Iterator&, Iterator const&)
    {
        return false;
    }

    //  No exponent
    template <typename Iterator, typename Attribute>
    static bool
    parse_exp_n(Iterator&, Iterator const&, Attribute&)
    {
        return false;
    }
};

int main(int argc, char **argv) {
   double d;
   char c;
   // no_exp is a real number parser that ignores exponents and has a double attribute
   boost::spirit::qi::real_parser<double, no_exp_policy<double> > no_exp;
   std::string tok = "7.123456E";
   bool success = boost::spirit::qi::parse( tok.cbegin(), tok.cend(), 
    no_exp >> boost::spirit::qi::char_("NESWnesw"), 
    d, c );
   if( success ) {
       if( c == 'W' || c == 'w' || c == 'S' || c == 's' ) {
           d = -d;
       }
       cout << d << " " << c << endl;
   }
   else
       cout << "failed" << endl;

   return 0;
}

Output:

7.12346 E

Hope this helps, though I agree it's a bit long-winded. I'm still not 100% sure it's not a spirit error that 7.12346E is handled by the default real parser as a real number, as IMHO you need to have an exponent value after the E to make it valid.

FatalFlaw
  • 1,077
  • 11
  • 19