从std :: string中解析整数,但如果是float则失败

时间:2016-08-30 12:01:39

标签: c++ c++11

在C ++和C中,有多种方法可以将字符串转换为整数,但我还没有找到解析浮点数时失败的转换方法。

const float fnum = std::stof("1.5");
std::cout << fnum << std::endl; // prints "1.5", all okay

const int inum = std::stoi("1.5");
std::cout << inum << std::endl; // prints "1", but wrong!

我需要这个来分析CSV文件的列类型。如果一列中的所有字段都是整数,则将列存储为std :: vector&lt; int&gt ;,如果是float,那么std :: vector&lt; float&gt;,否则将其存储为字符串。

唯一看起来很有希望的方法是:

std::string num = "1.5";
char *end = nullptr;

const long lnum = strtol(num.data(), &end, 10);
if (end != &*num.end()) {
    std::cout << "Float? " << l << " / " << num << std::endl;
} else {
    std::cout << "Integer! " << l << " / " << num << std::endl;
}

这很有效,但很难看。有没有C ++ - 解决这个问题的方法?

5 个答案:

答案 0 :(得分:4)

你可以使用boost lexical_cast。如果演员表失败,它会抛出异常

try
{
    number = boost::lexical_cast<int>(your_string);
}
catch (const boost::bad_lexical_cast& exec)
{
    // do something on fail
}

答案 1 :(得分:4)

你应该迭代检查数字是否作为整数解析1),2)作为浮点数,最后3)作为两者。但“解析”应该意味着消耗整个字符串。

尝试这样的事情:

#include <sstream>
#include <string>

bool TryAsInt(const std::string & s, long long int & out)
{
    std::istringstream iss(s);
    return (iss >> out >> std::ws) && (iss.get() == EOF);
}

同样适用于花车。

如果你不喜欢使用iostreams,你也可以使用std::strtollstd::strtod等。这样你也可以控制整数。例如:

#include <cerrno>
#include <cstdlib>
#include <string>

bool TryAsInt(const std::string & s, long long int & out)
{
    char * e;
    errno = 0;

    out = std::strtoll(s.data(), &e, 0);
    return errno == 0 && s.data() + s.size() == e;
}

然后你仍然必须将它与检查所有字段的逻辑结合起来。

例如:

std::vector<string> raw_fields;

long long int n;
double x;

if (std::all_of(raw_fields.begin(), raw_fields.end(),
    [&n](const string & s) { return TryAsInt(s, n); })
{
    // integer case
}
else if (std::all_of(raw_fields.begin(), raw_fields.end(),
    [&x](const string & s) { return TryAsFloat(s, x); })
{
    // floating point case
}
else
{
    // just use raw_fields as-is
}

答案 2 :(得分:1)

为此使用普通的std :: stoi,但请确保检查字符串是否已完全消耗。例如:

static bool isIntValue(const std::string& string, int32_t& intValue)
{
    try
    {
        size_t lastChar;
        intValue = std::stoi(string, &lastChar);
        return lastChar == string.size();
    }
    catch (...)
    {
        return false;
    }
}

此代码的执行速度比std :: istringstream解决方案快得多。

答案 3 :(得分:0)

如果您需要更多类型检查,请查看提升Spirit X3。 你可以这样做:

#include <boost/spirit/home/x3.hpp>
#include <iostream>
#include <string>

template<typename T, typename RuleType>
bool is_type(std::string const& str, RuleType const& rule, T& val)
{
    using namespace boost::spirit::x3;

    auto beg = std::begin(str);
    auto end = std::end(str);

    auto ret = parse(beg,end, rule, val);
    return ret && (beg==end);
}

int main(int argc, char** argv)
{
    std::string s1="1.0";
    float v;
    std::cout << s1 << " is int ?   : " << is_type(s1, boost::spirit::x3::int_, v) << "\n";
    std::cout << s1 << " is float ? : " << is_type(s1, boost::spirit::x3::float_, v) << "\n";



    return 0;
}

注意:您可以指定更严格的解析(请查看此处:https://github.com/djowel/spirit_x3/tree/master/include/boost/spirit/home/x3/numeric

答案 4 :(得分:-2)

您希望对包含十进制数的数字失败。您可以测试点,也可以测试十进制数字。

if (num.find('.') != string::npos || num.find(',') != string::npos)
   cout << "Number is not integer" << endl;

第二个选项:

double fnum = std::stod(num);
if (fnum != (long)fnum)
   cout << "Number is not integer" << endl;

您不应该担心浮点舍入错误,因为每个整数都可以精确地表示为加倍舍入为2 ^ 53.