0

I am using a TIVA TM4C to get messages about balance and expiry on a SIM card in a SIM900 cell phone modem.

Below is the code I am using to parse the string. I am concerned because the code relies on spaces being in specific locations. It seems like it would be more reliable if I could parse only for numbers, and based on order it would be simple to determine which was dollars, cents, month, etc.

Is there a better method I could use, to parse just for numbers? The currency isn't as essential.

Here is the code:

char *message = NULL;           // Balance and expiry message
char expiry[] = "00/00/00";     // Expiry date
char balance[] = "999.99";      // Remaining balance
char currency[] = "USD";        // Balance currency
char *ptr;                      // Pointer for parsing balance message 
int ctr=0;                      // For stepping through tokens

// Get the balance/expiry message
message = getMessage();

// The message will always look like this:
// +CUSD: 0,"Your account balance is 49.10 USD and will expire on 04/03/16.",64

// Parse
ptr = strtok (message," ");
while (ptr != NULL){
    ptr = strtok (NULL," ");
    if (ctr == 4) { strcpy(balance,ptr); }
    else if (ctr == 5) { strcpy(currency,ptr); }
    else if (ctr == 10) { strncpy(expiry,ptr,8); }
    ctr++;
}
LShaver
  • 285
  • 1
  • 5
  • 14
  • "The message will always look like this" - Seems safe then. When you're parsing strings you're always, at some level, assuming the structure of your input. You can hide that behind abstractions, but *something* has to know what the format is. There are of course safer ways to do it then your current implementation (which is C btw) – Ed S. Nov 20 '15 at 22:58
  • 1
    Use `std::istringstream` – πάντα ῥεῖ Nov 20 '15 at 22:58
  • Which version of `c++` are you using? If 11 or 14 then using [RegEx STL](http://en.cppreference.com/w/cpp/regex) library will allow you to write more flexible code. – ilya1725 Nov 21 '15 at 00:25
  • 1
    @ilya1725 char*, strtok, and NULL. His c++ version is c99 :P – Borgleader Nov 21 '15 at 00:55
  • @EdS. Looking through old questions today, thought I'd edit this one. Turns out I'm still using basically the same code, probably a few thousand times since then, and no parse errors yet - proving your point! – LShaver May 04 '16 at 06:24

1 Answers1

0

Or if you can use boost, consider Boost Spirit:

Live On Coliru

#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/date_time/gregorian/greg_date.hpp>
#include <boost/date_time/gregorian/gregorian_io.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>

int main() {
    using boost::gregorian::date;
    using Money = boost::multiprecision::number<boost::multiprecision::cpp_dec_float<20>, boost::multiprecision::et_off>;

    boost::gregorian::date expiry; // Expiry date
    Money balance;                 // Remaining balance
    std::string currency;          // Balance currency

    // The message will always look like this:
    for (std::string message : {
            "+CUSD: 0,\"Your account balance is 49.10 USD and will expire on 04/03/16.\",64",
        })
    {
        using namespace boost::spirit::x3;

        real_parser<Money> money_;
        int_parser<int, 10, 2, 2> int2_;

        auto to_date = [](auto& ctx) {
            using boost::fusion::at_c;
            auto& t = _attr(ctx);
            _val(ctx) = date(2000+at_c<2>(t), at_c<0>(t), at_c<1>(t));
        };

        auto date_  = rule<struct date_, date> { "date" }
                    = (int2_ >> '/' >> int2_ >> '/' >> int2_) [ to_date ];

        auto tied = std::tie(balance, currency, expiry);

        bool ok = phrase_parse(message.begin(), message.end(),
                omit [ *(char_ - "balance is") ]
                >> lexeme["balance is"] >> money_ >> lexeme[+graph]
                >> lexeme["and will expire on"] >> date_ >> omit[*char_] >> eoi,
                space, tied);

        assert(ok);
        std::cout << "Balance: "  << balance  << "\n";
        std::cout << "Currency: " << currency << "\n";
        std::cout << "Expiry: "   << expiry   << "\n";
    }
}

Prints

Balance: 49.1
Currency: USD
Expiry: 2016-Apr-03
sehe
  • 374,641
  • 47
  • 450
  • 633