首页 文章

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

提问于
浏览
2

在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 <int>,如果是float,则存储为std :: vector <float>,否则将其存储为字符串 .

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

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;
}

这有效,但非常难看 . 有没有解决这个问题的方法?

5 回答

  • -2

    你可以使用boost lexical_cast . 如果强制转换失败,它会抛出异常

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

    您应该迭代检查数字是否解析为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
    }
    
  • 3

    使用普通的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解决方案快得多 .

  • 4

    如果您需要更多类型检查,请查看boost 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

  • 0

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

    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 .

相关问题