如何验证字符串是否有效(即使它有一个点)?

时间:2015-03-20 14:40:03

标签: c++ string double

我一直在寻找一种方法来确定我的字符串值是否是一个有效的双倍,我还没有找到一种方法也不会拒绝带有一个点的数字......

在我的搜索中,我发现了这个

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

和Charles Salvia给出的答案是

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

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

9 个答案:

答案 0 :(得分:10)

你可能想要像这样使用std::stod

bool is_number(const std::string& s)
{
    try
    {
        std::stod(s);
    }
    catch(...)
    {
        return false;
    }
    return true;
}

但这可能效率很低,例如, zero-cost exceptions

所以使用@ Robinson的解决方案或strtod是一个更好的选择:

bool is_number(const std::string& s)
{
    char* end = 0;
    double val = strtod(s.c_str(), &end);
    return end != s.c_str() && val != HUGE_VAL;
}

答案 1 :(得分:3)

为什么不使用istringstream?

#include <sstream>

bool is_numeric (std::string const & str) 
{
    auto result = double();
    auto i = std::istringstream(str);

    i >> result;      
    i >> std::ws;  

    return !i.fail() && i.eof();
}

答案 2 :(得分:2)

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

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

如果你知道如何处理这个问题,你也可以使用正则表达式...

答案 3 :(得分:1)

您可以使用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

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

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

<强>输出:

true
false
true
false
true

答案 4 :(得分:0)

添加另一项支票c == '.'

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

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

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

    for (char c : s )
    {
       if ( !(std::isdigit(c) || c == '.' ) && dotCount > 1 )
       {
          return false;
       }
       dotCount += (c == '.');
    }

    return true;
}

答案 5 :(得分:0)

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

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

答案 6 :(得分:0)

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

bool const hasDoubleRepresentation( std::string const & str, double & d ) const {
std::stringstream sstr(str);
return !((sstr >> std::noskipws >> d).rdstate() ^ std::ios_base::eofbit);}

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

答案 7 :(得分:0)

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

#include <string>
#include <charconv>

bool string_is_number(const std::string& str)
{
    if (str.empty()) return false;
    double result;
    auto[ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), result);
    return (ec == std::errc());
}

成功转换后, std :: from_chars 返回 std :: errc()。从本质上讲,这只是包装 from_chars 并丢弃所得的double。根据您的用例,使用错误值并将其加倍(假设字符串稍后将转换为数字)可能会更有利,但是在那时,使用 from_chars 会更有意义。本身。

答案 8 :(得分:0)

这是我的解决方法:

bool isNumber(string s)
{
    for (int i = 0; i < s.length(); i++)
        if (isdigit(s[i]) == false && s[i] != '.')
            return false;

    return true;
}

它对我来说正常工作,您可以尝试一下!