在没有特殊库的情况下验证 C++ 中的浮点数
Validating Floating point in C++ without special libraries
我知道这个问题以前有人问过,但是答案没有解决我的问题所以我问这个问题
我有一个简单的程序来查找三个数中的最大值,它应该只接受浮点数。如果输入字符或字符串,需要显示错误,用户需要重新输入。
我有一个函数可以接受有效的浮动输入
float validInput()
{
float x;
cout<< flush;
cin >> x;
while(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
cout << "Not a numeric value please enter again\n";
cin >> x;
}
return x;
}
所以我在主函数中使用 validInput 进行输入,比如
int main()
{
float x = validInput();
float y = validInput();
float z = validInput();
findGreatest(x,y,z);
return 0;
}
此方法适用于大多数输入。当我输入一个数字后跟一个字符时,它失败了,validInput 函数奇怪地失败了。在给出这样的输入时,它会显示错误消息 "Not a numeric value please enter again" 但不会接受另一个输入,而是将字符之前的数值视为输入并存储它。我的要求是忽略整个输入并要求重新输入
据我了解
cin.ignore(numeric_limits<streamsize>::max(),'\n');
不会忽略在输入开头输入的数字,但只会清除流中的字符,即使 cin.fail() 为真。
有什么办法可以解决这个问题吗?它可能需要不同的参数 cin.ignore 虽然不确定。
提前致谢
来源:
PS:我不能使用像boost这样的特殊库。该代码用于实现软件测试的测试用例,因此它需要正确处理任何类型的输入。
std::cin
will read sequentially from the stream, so if the first chars represent a valid number, it thinks it's OK. If you want to make sure what you read is indeed just a number (not followed by some additional chars), one option is to read using std::getline
into a std::string
, then convert the string to a float using std::stof
(C++11)。后者将指向无法转换的第一个字符的位置的指针作为第二个参数。如果该位置小于字符串的长度,那么您的行包含的不仅仅是数字,因此输入无效。
示例:
#include <iostream>
int main()
{
float x;
std::size_t pos;
std::string str;
while (std::getline(std::cin, str))
{
try
{
x = std::stof(str, &pos);
}
catch(...)
{
std::cout << "Not a numeric value please enter again\n";
continue;
}
if(pos != str.length())
{
std::cout << "Not a numeric value please enter again\n";
continue;
}
break;
}
std::cout << x;
}
您可能想看看实际发生了什么,因为行为一点也不奇怪:当您在一行中输入一个浮点数后跟一个非数字时,浮点值被提取出来就好了。 validInput()
函数的失败案例是 not hit - 那个调用!但是,由于再次调用该函数时有些东西无法解析为浮点数,因此第二次调用会触发失败!
通过在 validInput()
调用之间添加输出,您可以看到这确实是行为。这样您就可以知道哪些调用实际产生了错误。在没有错误时存储值是预期的行为!
您可以通过读取一行并验证您可以从该行读取并且该行后面只有 space 以外的内容来确保该行不包含无效输入。例如:
float validInput()
{
float x;
// cout<< flush; There is *NO* reason to flush cout: it is flushed when using cin
for (std::string line; std::getline(std::cin, line); ) {
std::istringstream lin(line);
if (lin >> x && (lin >> std::ws).eof()) {
break;
}
cout << "Not a numeric value please enter again\n";
}
throw std::runtime_error("reached end of input before getting a valid value!");
return x;
}
使用 lin >> std::ws
会跳过该行所有可能的尾随白色 space(换行符已被 std::getline()
删除)。之后应该使用流并设置 eof()
标志,如果确实没有进一步的输入(这是 eof()
的少数有效用途之一...)。
我知道这个问题以前有人问过,但是答案没有解决我的问题所以我问这个问题
我有一个简单的程序来查找三个数中的最大值,它应该只接受浮点数。如果输入字符或字符串,需要显示错误,用户需要重新输入。
我有一个函数可以接受有效的浮动输入
float validInput()
{
float x;
cout<< flush;
cin >> x;
while(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
cout << "Not a numeric value please enter again\n";
cin >> x;
}
return x;
}
所以我在主函数中使用 validInput 进行输入,比如
int main()
{
float x = validInput();
float y = validInput();
float z = validInput();
findGreatest(x,y,z);
return 0;
}
此方法适用于大多数输入。当我输入一个数字后跟一个字符时,它失败了,validInput 函数奇怪地失败了。在给出这样的输入时,它会显示错误消息 "Not a numeric value please enter again" 但不会接受另一个输入,而是将字符之前的数值视为输入并存储它。我的要求是忽略整个输入并要求重新输入
据我了解
cin.ignore(numeric_limits<streamsize>::max(),'\n');
不会忽略在输入开头输入的数字,但只会清除流中的字符,即使 cin.fail() 为真。
有什么办法可以解决这个问题吗?它可能需要不同的参数 cin.ignore 虽然不确定。
提前致谢
来源:
PS:我不能使用像boost这样的特殊库。该代码用于实现软件测试的测试用例,因此它需要正确处理任何类型的输入。
std::cin
will read sequentially from the stream, so if the first chars represent a valid number, it thinks it's OK. If you want to make sure what you read is indeed just a number (not followed by some additional chars), one option is to read using std::getline
into a std::string
, then convert the string to a float using std::stof
(C++11)。后者将指向无法转换的第一个字符的位置的指针作为第二个参数。如果该位置小于字符串的长度,那么您的行包含的不仅仅是数字,因此输入无效。
示例:
#include <iostream>
int main()
{
float x;
std::size_t pos;
std::string str;
while (std::getline(std::cin, str))
{
try
{
x = std::stof(str, &pos);
}
catch(...)
{
std::cout << "Not a numeric value please enter again\n";
continue;
}
if(pos != str.length())
{
std::cout << "Not a numeric value please enter again\n";
continue;
}
break;
}
std::cout << x;
}
您可能想看看实际发生了什么,因为行为一点也不奇怪:当您在一行中输入一个浮点数后跟一个非数字时,浮点值被提取出来就好了。 validInput()
函数的失败案例是 not hit - 那个调用!但是,由于再次调用该函数时有些东西无法解析为浮点数,因此第二次调用会触发失败!
通过在 validInput()
调用之间添加输出,您可以看到这确实是行为。这样您就可以知道哪些调用实际产生了错误。在没有错误时存储值是预期的行为!
您可以通过读取一行并验证您可以从该行读取并且该行后面只有 space 以外的内容来确保该行不包含无效输入。例如:
float validInput()
{
float x;
// cout<< flush; There is *NO* reason to flush cout: it is flushed when using cin
for (std::string line; std::getline(std::cin, line); ) {
std::istringstream lin(line);
if (lin >> x && (lin >> std::ws).eof()) {
break;
}
cout << "Not a numeric value please enter again\n";
}
throw std::runtime_error("reached end of input before getting a valid value!");
return x;
}
使用 lin >> std::ws
会跳过该行所有可能的尾随白色 space(换行符已被 std::getline()
删除)。之后应该使用流并设置 eof()
标志,如果确实没有进一步的输入(这是 eof()
的少数有效用途之一...)。