我如何验证一个字符串是否是有效的双精度数字(即使它有一个点)?

问题描述 投票:10回答:9

我整夜忙于寻找一种方法来确定我的字符串值是否为有效的double值,但我还没有找到一种不会拒绝带有点的数字的方法...

在搜索中,我发现了这个

How to determine if a string is a number with C++?

和查尔斯·萨尔维亚给出的答案是

bool is_number(const std::string& s)
{
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}

这适用于其中没有点但被带点的数字拒绝的任何数字...

c++ string double
9个回答
12
投票

您可能会想像这样使用std::stod

std::stod

但是这可能效率很低,例如bool is_number(const std::string& s) { try { std::stod(s); } catch(...) { return false; } return true; }

因此使用@Robinson的解决方案或zero-cost exceptions是更好的选择:

strtod

4
投票

为什么不只使用istringstream?

strtod

2
投票

您可以使用bool is_number(const std::string& s) { char* end = 0; double val = strtod(s.c_str(), &end); return end != s.c_str() && *end == '\0' && val != HUGE_VAL; } 。通过不设置#include <sstream> bool is_numeric (std::string const & str) { auto result = double(); auto i = std::istringstream(str); i >> result; return !i.fail() && i.eof(); } 标志,它会告诉您数字后面是否有任何非数字。

std::istringstream()

输出:

eof()

模板版本:用于测试特定类型

bool is_number(const std::string& s)
{
    long double ld;
    return((std::istringstream(s) >> ld >> std::ws).eof());
}

int main()
{
    std::cout << std::boolalpha << is_number("   3.14") << '\n';
    std::cout << std::boolalpha << is_number("   3.14x") << '\n';
    std::cout << std::boolalpha << is_number("   3.14 ") << '\n';
}

输出:

true
false
true

2
投票

您还可以计算您的字符串包含多少点。如果此数字小于或等于1,并且所有其他字符均为数字,则您的字符串为有效的双精度数字。

template<typename Numeric>
bool is_number(const std::string& s)
{
    Numeric n;
    return((std::istringstream(s) >> n >> std::ws).eof());
}

int main()
{
    std::cout << std::boolalpha << is_number<int>("314") << '\n';
    std::cout << std::boolalpha << is_number<int>("3.14") << '\n';
    std::cout << std::boolalpha << is_number<float>("   3.14") << '\n';
    std::cout << std::boolalpha << is_number<double>("   3.14x") << '\n';
    std::cout << std::boolalpha << is_number<long double>("   3.14 ") << '\n';
}

如果知道如何处理正则表达式,也可以使用正则表达式...


0
投票

确保数字中最多有一个点。

true
false
true
false
true

0
投票

添加另一张支票bool isnumber(const string& s) { int nb_point=0; for (int i=0; i<s.length();i++) { if (s[i]=='.') { nb_point++; } else if (!isdigit(s[i]) { return false; } } if (nb_point<=1) { return true; } else { return false; } }

bool is_number(const std::string& s)
{
    if (s.empty())
       return false;

    bool sawDot = false;
    for (char c : s )
    {
       if ( !(std::isdigit(c) || (c == '.' && !sawDot) ) )
          return false;
       sawDot = sawDot || (c == '.');
    }

    return true;
}

您可以使用以下代码使代码更易于阅读:

c == '.'

0
投票

我非常反对在这种低级别操作中使用try-catch方法。相反,我在使用以下内容:

bool is_number(const std::string& s)
{
    return !s.empty() && std::find_if(s.begin(), 
    s.end(), [](char c) { return !(std::isdigit(c) || c == '.');  }) == s.end();
}

上面的优点是,如果返回true,则还将d设置为str中包含的数字。如果不需要此附加功能,则可以删除d作为输入参数。还应注意,如果str为“ 3.14”(即包含空格的数字),则存在noskipws(不跳过空白)的结果是它返回false。


0
投票

已经发布了一些答案,所以我想自己添加一个。如果您可以访问C ++ 17,则使用charconv可能是一种更有效的方法。我没有对此进行基准测试,但是对于大多数字符串转换应用程序,charconv效率很高。此解决方案还需要支持charconv到double或来自double的编译器。 VC ++支持这一点。我不确定其他哪些编译器已经实现了标准库的这一方面。


0
投票

这是我的解决方法:

© www.soinside.com 2019 - 2024. All rights reserved.