解析未知类型的数字字符串?

发布于 2025-01-07 05:22:59 字数 408 浏览 0 评论 0原文

当事先不知道目标类型时,将 std::string 解析为 C++ 中的某些数字类型的最佳方法是什么?

我看过 lexical_cast< /a>,但这将目标类型作为模板参数。我可以编写包装函数,通过捕获 bad_lexical_cast 并返回 false 来滥用此功能,但这看起来很难看。

我的输入值通常是 intfloat 并且具有非常简单的格式,但是灵活的东西会很棒!

What's the best approach to parsing std::string to some numeric type in C++, when the target type isn't known in advance?

I've looked at lexical_cast, but that takes the target type as a template parameter. I could write wrapper functions that abuse this by catching bad_lexical_cast and returning false, but that seems ugly.

My input values will typically be int or float and have extremely simple formatting, but something that's flexible would be great!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

终陌 2025-01-14 05:22:59

您可以使用 Boost Spirit 数值解析器 或(滥用)使用 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;
}

You could use either Boost Spirit Numerical Parsers or (ab)use Boost Lexicalcast.

Boost Spirit allows you fine grained control of the format accepted, see e.g.

Here is a quick demo, that also shows how you could detect several possible numeric input formats (progressively) and return the type that was matched. Of course that could be overkill, but it should demonstrate how to use Spirit further.

The demo also shows how to advance the input iterator so you can easily continue parsing where the numeric input ended.

#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;
}
乖乖哒 2025-01-14 05:22:59

当您实际解析数据以进行转换时,您需要知道
输入要放入结果的内容; 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正则表达式。)

When you actually parse the data to convert it, you need to know the
type in which to put the results; C++ is a statically typed language,
and there's no way around that. If you have a string, and want to know
what type it is, using regular expressions is a simple solution:

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

should match any possible floating point value, and:

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

matches an integer in any base. (Supposing the default configuration of Boost or the C++11 regular expressions.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文