Разбор числовых строк неизвестного типа? - PullRequest
2 голосов
/ 20 февраля 2012

Каков наилучший подход к синтаксическому анализу std::string для какого-либо числового типа в C ++, когда целевой тип не известен заранее?

Я смотрел на lexical_cast , нокоторый принимает целевой тип в качестве параметра шаблона.Я мог бы написать функции-обертки, которые злоупотребляют этим, перехватывая bad_lexical_cast и возвращая false, но это кажется уродливым.

Мои входные значения обычно будут int или float и имеют чрезвычайно простое форматирование, ночто-то гибкое было бы здорово!

Ответы [ 2 ]

3 голосов
/ 20 февраля 2012

Вы можете использовать Boost Spirit Числовые парсеры или (ab) использовать Boost Lexicalcast.

Boost Spirit позволяет детально контролировать принятый формат, см., Например,

Вот краткая демонстрация, в которой также показано, как можно определить несколько возможных числовых форматов ввода ( постепенно ) и вернуть соответствующий тип. Конечно, это может быть излишним, но это должно продемонстрировать, как дальше использовать Дух.

Демонстрация также показывает, как продвинуть итератор ввода, чтобы вы могли легко продолжить синтаксический анализ там, где закончился числовой ввод.

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

enum numeric_types
{
    fmt_none,
    fmt_float,
    fmt_double,
    fmt_uint,
    fmt_int,
    // fmt_hex, etc. 
};

template <typename It>
    bool is_numeric(It& f, It l, numeric_types& detected)
{
    return qi::phrase_parse(f,l,
            qi::uint_   [ qi::_val = fmt_uint   ]
          | qi::int_    [ qi::_val = fmt_int    ]
          | qi::float_  [ qi::_val = fmt_float  ]
          | qi::double_ [ qi::_val = fmt_double ]
           ,qi::space, detected);
}

template <typename It>
    bool is_numeric(It& f, It l)
{
    numeric_types detected = fmt_none;
    return is_numeric(f, l, detected);
}

int main()
{
    const std::string input = "124, -25, 582";
    std::string::const_iterator it = input.begin();

    bool ok = is_numeric(it, input.end());

    if (ok)   
    {
        std::cout << "parse success\n";
        if (it!=input.end()) 
            std::cerr << "trailing unparsed: '" << std::string(it,input.end()) << "'\n";
    }
    else 
        std::cerr << "parse failed: '" << std::string(it,input.end()) << "'\n";

    return ok? 0 : 255;
}
1 голос
/ 20 февраля 2012

Когда вы на самом деле анализируете данные для их преобразования, вам нужно знать тип, в который нужно поместить результаты;C ++ является статически типизированным языком, и нет пути к этому.Если у вас есть строка и вы хотите знать, какой это тип, использование регулярных выражений является простым решением:

"\\s*[+-]?(?:"
    "\\d+\\.\\d*(?:[Ee][+-]?\\d+)?"
    "|\\.\\d+(?:[Ee][+-]?\\d+)?"
    "|\\d+[Ee][+-]?\\d+"
")"

должно соответствовать любому возможному значению с плавающей запятой и:

"\\s*[+-]?(?:"
    "[1-9][0-9]*"
    "|0[0-7]*"
    "|0x[0-9a-fA-F]+"
)"

соответствует целому числу в любой базе.(Предположим, что по умолчанию используется конфигурация Boost или регулярные выражения C ++ 11.)

...