我整夜忙于寻找一种方法来确定我的字符串值是否为有效的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();
}
这适用于其中没有点但被带点的数字拒绝的任何数字...
您可能会想像这样使用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
为什么不只使用istringstream?
strtod
您可以使用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
您还可以计算您的字符串包含多少点。如果此数字小于或等于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';
}
如果知道如何处理正则表达式,也可以使用正则表达式...
确保数字中最多有一个点。
true
false
true
false
true
添加另一张支票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 == '.'
我非常反对在这种低级别操作中使用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。
已经发布了一些答案,所以我想自己添加一个。如果您可以访问C ++ 17,则使用charconv可能是一种更有效的方法。我没有对此进行基准测试,但是对于大多数字符串转换应用程序,charconv效率很高。此解决方案还需要支持charconv到double或来自double的编译器。 VC ++支持这一点。我不确定其他哪些编译器已经实现了标准库的这一方面。
这是我的解决方法: